starting uart and refactoring
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -173,9 +173,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.17"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
|
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
@@ -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 cortex_m_rt::entry;
|
||||||
use driver_and_task_library::{
|
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]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let board = setup_board();
|
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(
|
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();
|
||||||
|
BIN
src/.DS_Store
vendored
Normal file
BIN
src/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -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;
|
use core::arch::asm;
|
||||||
impl UsableBoard {
|
|
||||||
pub fn setup_gpio_port(&mut self, port: Port, options: PortOptions) -> UsablePort {
|
use crate::gpio::ports::{
|
||||||
setup_gpio_port(port, options)
|
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
|
pub(crate) const fn run_mode_clock_gate_control_1(&self) -> *mut u32 {
|
||||||
// TODO: impl Drop trait so that tasks all run before the main function ends?
|
const OFFSET: u32 = 0x104;
|
||||||
// TODO: examine page 670 for when (if) I do interrupts
|
(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 {
|
pub fn setup_board() -> UsableBoard {
|
||||||
UsableBoard
|
UsableBoard { board: Board }
|
||||||
}
|
}
|
||||||
|
@@ -1,17 +1,11 @@
|
|||||||
use crate::{memory, H, L};
|
use crate::{
|
||||||
|
memory,
|
||||||
|
utils::{pins_to_bits, reverse_array},
|
||||||
|
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,
|
||||||
@@ -23,11 +17,6 @@ pub enum Pin {
|
|||||||
Six = 6,
|
Six = 6,
|
||||||
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,
|
||||||
@@ -58,22 +47,21 @@ impl<const N: usize> ReadablePins<N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_all(&self) -> [bool; N] {
|
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)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct ReadablePin {
|
pub struct ReadablePin {
|
||||||
data_address: *mut u32,
|
data_address: *mut u32,
|
||||||
bit: Pin,
|
pin: Pin,
|
||||||
}
|
}
|
||||||
impl ReadablePin {
|
impl ReadablePin {
|
||||||
pub fn read(&self) -> bool {
|
pub fn read(&self) -> bool {
|
||||||
let current = unsafe { memory::read(self.data_address) };
|
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 struct WritablePinOptions {
|
||||||
pub function: Function,
|
pub function: Function,
|
||||||
}
|
}
|
||||||
@@ -87,13 +75,13 @@ impl<const N: usize> WritablePins<N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_all(&self) -> [bool; N] {
|
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]) {
|
pub fn write_all(&mut self, values: [bool; N]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
memory::write_bits(
|
memory::write_bits(
|
||||||
self.data_address,
|
self.data_address,
|
||||||
&self.pins.map(|pin| pin.bit as u32),
|
&self.pins.map(|pin| pin.pin as u32),
|
||||||
values,
|
values,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -104,17 +92,17 @@ impl<const N: usize> WritablePins<N> {
|
|||||||
|
|
||||||
pub fn clear_all(&mut self) {
|
pub fn clear_all(&mut self) {
|
||||||
unsafe {
|
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) {
|
pub fn set_all(&mut self) {
|
||||||
unsafe {
|
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) {
|
pub fn toggle_all(&mut self) {
|
||||||
unsafe {
|
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<const N: usize> WritablePins<N> {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct WritablePin {
|
pub struct WritablePin {
|
||||||
data_address: *mut u32,
|
data_address: *mut u32,
|
||||||
bit: Pin,
|
pin: Pin,
|
||||||
}
|
}
|
||||||
impl WritablePin {
|
impl WritablePin {
|
||||||
pub fn read(&self) -> bool {
|
pub fn read(&self) -> bool {
|
||||||
let current = unsafe { memory::read(self.data_address) };
|
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) {
|
pub fn clear(&mut self) {
|
||||||
unsafe {
|
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) {
|
pub fn set(&mut self) {
|
||||||
unsafe {
|
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) {
|
pub fn toggle(&mut self) {
|
||||||
unsafe {
|
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
|
/// Page 684 of the data sheet for how the lock mechanism works
|
||||||
const UNLOCK: u32 = 0x4C4F434B;
|
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<const N: usize>(
|
fn setup_pins<const N: usize>(
|
||||||
port: Port,
|
port: Port,
|
||||||
pins: [Pin; N],
|
pins: [Pin; N],
|
||||||
@@ -159,18 +149,6 @@ fn setup_pins<const N: usize>(
|
|||||||
// Unlock the pins
|
// Unlock the pins
|
||||||
unsafe {
|
unsafe {
|
||||||
memory::write(port.lock(), UNLOCK);
|
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)
|
// Set to output pins if output (otherwise set to input)
|
||||||
@@ -184,27 +162,14 @@ fn setup_pins<const N: usize>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_values = reverse_array(match function {
|
// Disable alternate function when it's not used (and enable it when it is)
|
||||||
Function::Analog => todo!(),
|
if let Function::Analog | Function::Digital = function {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
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<const N: usize>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states
|
// TODO / WIP: commit here?!
|
||||||
|
unsafe {
|
||||||
// Disable alternate function when it's not used (and enable it when it is)
|
memory::set_bits(port.commit(), &pins_to_bits(&pins));
|
||||||
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));
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable digital function when it's needed (and disable it when it's not)
|
// Enable digital function when it's needed (and disable it when it's not)
|
||||||
@@ -246,7 +204,53 @@ fn setup_pins<const N: usize>(
|
|||||||
Function::Analog => unsafe {
|
Function::Analog => unsafe {
|
||||||
memory::clear_bits(port.digital_enable(), &pins_to_bits(&pins));
|
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<const N: usize>(
|
|||||||
setup_pins(port, pins, false, options.function, options.pull);
|
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 });
|
let pins: [ReadablePin; N] = pins.map(|pin| ReadablePin { data_address, pin });
|
||||||
ReadablePins { data_address, pins }
|
ReadablePins { data_address, pins }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,9 +274,6 @@ pub fn setup_writable_pins<const N: usize>(
|
|||||||
setup_pins(port, pins, true, options.function, Pull::Neither);
|
setup_pins(port, pins, true, options.function, Pull::Neither);
|
||||||
|
|
||||||
let data_address = port.data(&pins);
|
let data_address = port.data(&pins);
|
||||||
let pins: [WritablePin; N] = pins.map(|pin| WritablePin {
|
let pins: [WritablePin; N] = pins.map(|pin| WritablePin { data_address, pin });
|
||||||
data_address,
|
|
||||||
bit: pin,
|
|
||||||
});
|
|
||||||
WritablePins { data_address, pins }
|
WritablePins { data_address, pins }
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
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};
|
use super::pins::{setup_readable_pins, setup_writable_pins};
|
||||||
@@ -14,13 +14,13 @@ pub enum Port {
|
|||||||
F,
|
F,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PortOptions;
|
pub struct GPIOPortOptions;
|
||||||
|
|
||||||
impl Port {
|
impl Port {
|
||||||
/// The starting point of memory addresses corresponding to this GPIO register
|
/// The starting point of memory addresses corresponding to this GPIO register
|
||||||
///
|
///
|
||||||
/// Modeled after page 660 of data sheet (GPIO Register Map)
|
/// Modeled after page 660 of data sheet (GPIO Register Map)
|
||||||
fn base(&self) -> u32 {
|
const fn base(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Port::A => 0x4000_4000,
|
Port::A => 0x4000_4000,
|
||||||
Port::B => 0x4000_5000,
|
Port::B => 0x4000_5000,
|
||||||
@@ -34,7 +34,7 @@ impl Port {
|
|||||||
/// The memory address of the alternate function select (AFSEL) register for this port
|
/// The memory address of the alternate function select (AFSEL) register for this port
|
||||||
///
|
///
|
||||||
/// Page 671 of data sheet
|
/// 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;
|
const OFFSET: u32 = 0x420;
|
||||||
(self.base() + OFFSET) as *mut u32
|
(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
|
/// The memory address of the analog mode select (AMSEL) register for this port
|
||||||
///
|
///
|
||||||
/// Page 687 of data sheet
|
/// 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;
|
const OFFSET: u32 = 0x52C;
|
||||||
(self.base() + OFFSET) as *mut u32
|
(self.base() + OFFSET) as *mut u32
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ impl Port {
|
|||||||
/// The memory address of the commit (CR) register for this port
|
/// The memory address of the commit (CR) register for this port
|
||||||
///
|
///
|
||||||
/// Page 685 of data sheet
|
/// Page 685 of data sheet
|
||||||
pub(super) fn commit(&self) -> *mut u32 {
|
pub(super) const fn commit(&self) -> *mut u32 {
|
||||||
const OFFSET: u32 = 0x524;
|
const OFFSET: u32 = 0x524;
|
||||||
(self.base() + OFFSET) as *mut u32
|
(self.base() + OFFSET) as *mut u32
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ impl Port {
|
|||||||
/// The memory address of the digital enable (DEN) register for this port
|
/// The memory address of the digital enable (DEN) register for this port
|
||||||
///
|
///
|
||||||
/// Page 682 of data sheet
|
/// 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;
|
const OFFSET: u32 = 0x51C;
|
||||||
(self.base() + OFFSET) as *mut u32
|
(self.base() + OFFSET) as *mut u32
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ impl Port {
|
|||||||
/// The memory address of the direction (DIR) register for this port
|
/// The memory address of the direction (DIR) register for this port
|
||||||
///
|
///
|
||||||
/// Page 663 of data sheet
|
/// Page 663 of data sheet
|
||||||
pub(super) fn direction(&self) -> *mut u32 {
|
pub(super) const fn direction(&self) -> *mut u32 {
|
||||||
const OFFSET: u32 = 0x400;
|
const OFFSET: u32 = 0x400;
|
||||||
(self.base() + OFFSET) as *mut u32
|
(self.base() + OFFSET) as *mut u32
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ impl Port {
|
|||||||
/// The memory address of the lock (LOCK) register
|
/// The memory address of the lock (LOCK) register
|
||||||
///
|
///
|
||||||
/// Page 684 of data sheet
|
/// Page 684 of data sheet
|
||||||
pub(super) fn lock(&self) -> *mut u32 {
|
pub(super) const fn lock(&self) -> *mut u32 {
|
||||||
const OFFSET: u32 = 0x520;
|
const OFFSET: u32 = 0x520;
|
||||||
(self.base() + OFFSET) as *mut u32
|
(self.base() + OFFSET) as *mut u32
|
||||||
}
|
}
|
||||||
@@ -100,21 +100,21 @@ impl Port {
|
|||||||
/// The memory address of the port control (PCTL) register for this port
|
/// The memory address of the port control (PCTL) register for this port
|
||||||
///
|
///
|
||||||
/// Page 688 of data sheet
|
/// 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;
|
const OFFSET: u32 = 0x52C;
|
||||||
(self.base() + OFFSET) as *mut u32
|
(self.base() + OFFSET) as *mut u32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The memory address of the pull-down resistor select (PDR) register for this port
|
/// The memory address of the pull-down resistor select (PDR) register for this port
|
||||||
/// Page 679 of data sheet
|
/// 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;
|
const OFFSET: u32 = 0x514;
|
||||||
(self.base() + OFFSET) as *mut u32
|
(self.base() + OFFSET) as *mut u32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The memory address of the pull-up resistor select (PUR) register for this port
|
/// The memory address of the pull-up resistor select (PUR) register for this port
|
||||||
/// Page 677 of data sheet
|
/// 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;
|
const OFFSET: u32 = 0x510;
|
||||||
(self.base() + OFFSET) as *mut u32
|
(self.base() + OFFSET) as *mut u32
|
||||||
}
|
}
|
||||||
@@ -125,8 +125,8 @@ impl Port {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Port {
|
impl Port {
|
||||||
/// The corresponding bit for this port in system's run-mode clock gate control (RCGC) register
|
/// The corresponding bit for this port in the system's GPIO Run mode clock gating control (RCGCGPIO) register
|
||||||
fn run_mode_clock_gate_control(&self) -> u32 {
|
const fn run_mode_clock_gate_control(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Port::A => 0,
|
Port::A => 0,
|
||||||
Port::B => 1,
|
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 {
|
unsafe {
|
||||||
memory::set_bits(
|
memory::set_bits(
|
||||||
registers::system::RCGCGPIO,
|
board.gpio_run_mode_clock_gate_control(),
|
||||||
&[port.run_mode_clock_gate_control() as u32],
|
&[port.run_mode_clock_gate_control()],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use crate::L;
|
pub unsafe fn read(address: *const u32) -> u32 {
|
||||||
|
|
||||||
pub unsafe fn read(address: *mut u32) -> u32 {
|
|
||||||
ptr::read_volatile(address)
|
ptr::read_volatile(address)
|
||||||
}
|
}
|
||||||
pub unsafe fn write(address: *mut u32, new: u32) {
|
pub unsafe fn write(address: *mut u32, new: u32) {
|
||||||
@@ -15,29 +13,20 @@ pub unsafe fn update<Updater: Fn(u32) -> u32>(address: *mut u32, updater: Update
|
|||||||
write(address, updater(read(address)));
|
write(address, updater(read(address)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn read_bits<const N: usize>(address: *mut u32, bits: &[u32; N]) -> [bool; N] {
|
pub unsafe fn read_bits<const N: usize>(address: *const u32, bits: &[u32; N]) -> [bool; N] {
|
||||||
let current = read(address);
|
let current = read(address);
|
||||||
let mut result = [L; N];
|
|
||||||
|
|
||||||
// TODO: look up accumulate or reduce or something
|
bits.map(|bit| current & (1 << bit) != 0)
|
||||||
for (i, bit) in bits.iter().enumerate() {
|
|
||||||
result[i] = (current & (1 << bit)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
pub unsafe fn write_bits<const N: usize>(address: *mut u32, bits: &[u32; N], values: [bool; N]) {
|
pub unsafe fn write_bits<const N: usize>(address: *mut u32, bits: &[u32; N], values: [bool; N]) {
|
||||||
update(address, |current| {
|
update(address, |current| {
|
||||||
let mut new = current;
|
bits.iter().zip(values).fold(current, |result, (bit, set)| {
|
||||||
// TODO: look up accumulate or reduce or something
|
|
||||||
for (bit, set) in bits.iter().zip(values) {
|
|
||||||
if set {
|
if set {
|
||||||
new |= 1 << bit;
|
result | (1 << bit)
|
||||||
} else {
|
} else {
|
||||||
new &= !(1 << bit);
|
result & !(1 << bit)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
new
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,37 +40,17 @@ pub unsafe fn update_bits<Updater: Fn([bool; N]) -> [bool; N], const N: usize>(
|
|||||||
|
|
||||||
pub unsafe fn set_bits(address: *mut u32, bits: &[u32]) {
|
pub unsafe fn set_bits(address: *mut u32, bits: &[u32]) {
|
||||||
update(address, |current| {
|
update(address, |current| {
|
||||||
let mut new = current;
|
bits.iter().fold(current, |result, bit| result | (1 << bit))
|
||||||
|
|
||||||
// TODO: look up accumulate or reduce or something
|
|
||||||
for bit in bits {
|
|
||||||
new |= 1 << bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
new
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub unsafe fn clear_bits(address: *mut u32, bits: &[u32]) {
|
pub unsafe fn clear_bits(address: *mut u32, bits: &[u32]) {
|
||||||
update(address, |current| {
|
update(address, |current| {
|
||||||
let mut new = current;
|
bits.iter()
|
||||||
|
.fold(current, |result, bit| result & !(1 << bit))
|
||||||
// TODO: look up accumulate or reduce or something
|
|
||||||
for bit in bits {
|
|
||||||
new &= !(1 << bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
new
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub unsafe fn toggle_bits(address: *mut u32, bits: &[u32]) {
|
pub unsafe fn toggle_bits(address: *mut u32, bits: &[u32]) {
|
||||||
update(address, |current| {
|
update(address, |current| {
|
||||||
let mut new = current;
|
bits.iter().fold(current, |result, bit| result ^ (1 << bit))
|
||||||
|
|
||||||
// TODO: look up accumulate or reduce or something
|
|
||||||
for bit in bits {
|
|
||||||
new ^= 1 << bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
new
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,8 @@
|
|||||||
mod board;
|
mod board;
|
||||||
mod gpio;
|
mod gpio;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod registers;
|
mod uart;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
pub use board::*;
|
pub use board::*;
|
||||||
pub use gpio::pins::*;
|
pub use gpio::pins::*;
|
||||||
|
@@ -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
|
|
183
src/lib/uart.rs
Normal file
183
src/lib/uart.rs
Normal file
@@ -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 }
|
||||||
|
}
|
15
src/lib/utils.rs
Normal file
15
src/lib/utils.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use crate::Pin;
|
||||||
|
|
||||||
|
pub fn pins_to_bits<const N: usize>(pins: &[Pin; N]) -> [u32; N] {
|
||||||
|
pins.map(|pin| pin as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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
|
||||||
|
}
|
125
src/main.rs
125
src/main.rs
@@ -54,7 +54,8 @@ static HEAP: BumpPointerAlloc = BumpPointerAlloc {
|
|||||||
end: 0x2000_0200,
|
end: 0x2000_0200,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[macro_use]
|
// TODO: remove or fix
|
||||||
|
// #[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
use alloc::string::String;
|
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 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, GPIOPortOptions, Pin, Port, Pull, ReadablePinOptions,
|
||||||
WritablePinOptions, H, L, Pull,
|
WritablePinOptions, H, L,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SYSCTL_RCGC1_R: *mut u32 = 0x400FE104 as *mut u32;
|
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;
|
const UART0_DR_R: *mut u32 = 0x4000C000 as *mut u32;
|
||||||
|
/// UART0 flag register
|
||||||
const UART0_FR_R: *mut u32 = 0x4000C018 as *mut u32;
|
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;
|
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;
|
const UART0_FBRD_R: *mut u32 = 0x4000C028 as *mut u32;
|
||||||
|
/// UART0 line control register
|
||||||
const UART0_LCRH_R: *mut u32 = 0x4000C02C as *mut u32;
|
const UART0_LCRH_R: *mut u32 = 0x4000C02C as *mut u32;
|
||||||
|
/// UART0 control register
|
||||||
const UART0_CTL_R: *mut u32 = 0x4000C030 as *mut u32;
|
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
|
|
||||||
const SYSCTL_RCGC2_GPIOA: u32 = 0x00000001;
|
|
||||||
/// UART Enable
|
/// UART Enable
|
||||||
const UART_CTL_UARTEN: u32 = 0x00000001;
|
const UART_CTL_UARTEN: u32 = 0x00000001;
|
||||||
/// 8 bit word length
|
/// 8 bit word length
|
||||||
@@ -109,18 +102,21 @@ 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: &mut UsableBoard) {
|
fn uart0_init() {
|
||||||
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,
|
||||||
);
|
);
|
||||||
|
// write_color(MAGENTA);
|
||||||
|
|
||||||
// activate port A
|
// For some reason, 7 no-ops are needed to stall the CPU while UART is enabled
|
||||||
// ptr::write_volatile(SYSCTL_RCGC2_R, ptr::read_volatile(SYSCTL_RCGC2_R) | SYSCTL_RCGC2_GPIOA);
|
for _ in 0..7 {
|
||||||
// ^ commented in favor of v
|
asm!("nop");
|
||||||
board.setup_gpio_port(Port::A, PortOptions);
|
}
|
||||||
|
|
||||||
|
// TODO / WIP: done up to here
|
||||||
|
|
||||||
// disable UART while setting it up
|
// disable UART while setting it up
|
||||||
ptr::write_volatile(
|
ptr::write_volatile(
|
||||||
@@ -128,7 +124,6 @@ fn uart0_init(board: &mut UsableBoard) {
|
|||||||
ptr::read_volatile(UART0_CTL_R) & !UART_CTL_UARTEN,
|
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)
|
// 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);
|
||||||
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)
|
// 8 bit word length (no parity bits, one stop bit, FIFOs)
|
||||||
// ptr::write_volatile(UART0_LCRH_R, UART_LCRH_WLEN_8|UART_LCRH_FEN);
|
// ptr::write_volatile(UART0_LCRH_R, UART_LCRH_WLEN_8|UART_LCRH_FEN);
|
||||||
// 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
|
// enable UART since it's been set up
|
||||||
ptr::write_volatile(
|
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 {
|
loop {
|
||||||
let fr = unsafe { ptr::read_volatile(UART0_FR_R) };
|
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() {
|
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 WHITE: [bool; 3] = [H, H, H];
|
||||||
const BLACK: [bool; 3] = [L, L, L];
|
const BLACK: [bool; 3] = [L, L, L];
|
||||||
|
|
||||||
@@ -195,25 +201,8 @@ const MAGENTA: [bool; 3] = [H, L, H];
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let mut board = setup_board();
|
let mut board = setup_board();
|
||||||
let mut port_a = board.setup_gpio_port(Port::A, PortOptions);
|
let mut port_a = board.setup_gpio_port(Port::A, GPIOPortOptions);
|
||||||
let mut port_f = board.setup_gpio_port(Port::F, PortOptions);
|
let mut port_f = board.setup_gpio_port(Port::F, GPIOPortOptions);
|
||||||
|
|
||||||
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],
|
||||||
@@ -222,8 +211,6 @@ fn main() -> ! {
|
|||||||
pull: Pull::Up,
|
pull: Pull::Up,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let [_sw1, _sw2] = switches.pins();
|
|
||||||
|
|
||||||
let mut rgb_led = port_f.setup_writable_pins(
|
let mut rgb_led = port_f.setup_writable_pins(
|
||||||
[Pin::One, Pin::Three, Pin::Two],
|
[Pin::One, Pin::Three, Pin::Two],
|
||||||
WritablePinOptions {
|
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];
|
let rainbow = [RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA];
|
||||||
|
|
||||||
// TODO: WIP: debugging
|
// 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 = String::from("\r\ntesting a static string!!!\r\n\r\n\r\n");
|
||||||
// let s = format!("Format");
|
uart0_out_string_blocking(&s);
|
||||||
// let s: String = rainbow.into();
|
|
||||||
uart0_out_string(&s);
|
|
||||||
|
|
||||||
loop {
|
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() {
|
match switches.read_all() {
|
||||||
[L, L] => rgb_led.write_all(WHITE),
|
[L, L] => rgb_led.write_all(WHITE),
|
||||||
[L, H] => rgb_led.write_all(BLUE),
|
[L, H] => rgb_led.write_all(BLUE),
|
||||||
@@ -252,10 +254,15 @@ fn main() -> ! {
|
|||||||
|
|
||||||
// uart0_out_string(&format!("The switches read {:?}", switches.read_all()));
|
// uart0_out_string(&format!("The switches read {:?}", switches.read_all()));
|
||||||
|
|
||||||
for _ in 0..1000000 {
|
// for _ in 0..1000000 {
|
||||||
unsafe {
|
// unsafe {
|
||||||
asm!("nop");
|
// 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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user