starting uart and refactoring

This commit is contained in:
J / Jacob Babich
2022-04-22 03:11:45 -04:00
parent e809e84afc
commit 18e9a5d7de
12 changed files with 436 additions and 228 deletions

4
Cargo.lock generated
View File

@@ -173,9 +173,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.17"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]

View File

@@ -5,19 +5,20 @@ use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch
use cortex_m_rt::entry;
use driver_and_task_library::{
setup_board, Function, Pin, Port, PortOptions, ReadablePinOptions, WritablePinOptions, H, L,
setup_board, Function, GPIOPortOptions, Pin, Port, Pull, ReadablePinOptions,
WritablePinOptions, H, L,
};
#[entry]
fn main() -> ! {
let board = setup_board();
let port_f = board.setup_gpio_port(Port::F, PortOptions);
let port_f = board.setup_gpio_port(Port::F, GPIOPortOptions);
let switches = port_f.setup_readable_pins(
[Pin::Zero, Pin::Four],
ReadablePinOptions {
function: Function::Digital,
pull_up: Some(true),
pull: Pull::Up,
},
);
let [_sw1, _sw2] = switches.pins();

BIN
src/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -1,18 +1,64 @@
use crate::gpio::ports::{setup_gpio_port, Port, PortOptions, UsablePort};
//! Data sheet: https://www.ti.com/lit/ds/spms376e/spms376e.pdf
pub struct UsableBoard;
impl UsableBoard {
pub fn setup_gpio_port(&mut self, port: Port, options: PortOptions) -> UsablePort {
setup_gpio_port(port, options)
use core::arch::asm;
use crate::gpio::ports::{
setup_port as setup_gpio_port, GPIOPortOptions, Port as GPIOPort, UsablePort as UsableGPIOPort,
};
use crate::uart::{
setup_port as setup_uart_port, Port as UARTPort, PortOptions as UARTPortOptions,
UsablePort as UsableUARTPort,
};
/// The board
///
/// Houses memory addresses of registers
#[derive(Clone, Copy)]
pub struct Board;
impl Board {
/// Page 231 of data sheet
const fn base(&self) -> u32 {
0x400F_E000
}
// TODO: have a no_op function here if so desired
/// The memory address of the GPIO Run mode clock gating control (RCGCGPIO) register for this port
///
/// Page 340 of data sheet
pub(crate) const fn gpio_run_mode_clock_gate_control(&self) -> *mut u32 {
const OFFSET: u32 = 0x608;
(self.base() + OFFSET) as *mut u32
}
// TODO: check page 704 for timers
// TODO: impl Drop trait so that tasks all run before the main function ends?
// TODO: examine page 670 for when (if) I do interrupts
pub(crate) const fn run_mode_clock_gate_control_1(&self) -> *mut u32 {
const OFFSET: u32 = 0x104;
(self.base() + OFFSET) as *mut u32
}
}
/// A setup version of the board that GPIO and UART ports (TODO: say more features when I make those) can be set up on
pub struct UsableBoard {
board: Board,
}
impl UsableBoard {
fn no_op(&self) {
unsafe {
asm!("nop");
}
}
}
impl UsableBoard {
pub fn setup_gpio_port(&mut self, port: GPIOPort, options: GPIOPortOptions) -> UsableGPIOPort {
setup_gpio_port(self.board, port, options)
}
pub fn setup_uart_port(&mut self, port: UARTPort, options: UARTPortOptions) -> UsableUARTPort {
setup_uart_port(self.board, port, options, &|| self.no_op())
}
}
pub fn setup_board() -> UsableBoard {
UsableBoard
UsableBoard { board: Board }
}

View File

@@ -1,17 +1,11 @@
use crate::{memory, H, L};
use crate::{
memory,
utils::{pins_to_bits, reverse_array},
H, L,
};
use super::ports::Port;
fn reverse_array<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)]
pub enum Pin {
Zero = 0,
@@ -23,11 +17,6 @@ pub enum Pin {
Six = 6,
Seven = 7,
}
fn pins_to_bits<const N: usize>(pins: &[Pin; N]) -> [u32; N] {
pins.map(|pin| pin as u32)
}
pub enum Function {
Analog,
Digital,
@@ -58,22 +47,21 @@ impl<const N: usize> ReadablePins<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)]
pub struct ReadablePin {
data_address: *mut u32,
bit: Pin,
pin: Pin,
}
impl ReadablePin {
pub fn read(&self) -> bool {
let current = unsafe { memory::read(self.data_address) };
current & (1 << self.bit as u32) != 0
current & (1 << self.pin as u32) != 0
}
}
pub struct WritablePinOptions {
pub function: Function,
}
@@ -87,13 +75,13 @@ impl<const N: usize> WritablePins<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]) {
unsafe {
memory::write_bits(
self.data_address,
&self.pins.map(|pin| pin.bit as u32),
&self.pins.map(|pin| pin.pin as u32),
values,
)
}
@@ -104,17 +92,17 @@ impl<const N: usize> WritablePins<N> {
pub fn clear_all(&mut self) {
unsafe {
memory::clear_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32));
memory::clear_bits(self.data_address, &self.pins.map(|pin| pin.pin as u32));
}
}
pub fn set_all(&mut self) {
unsafe {
memory::set_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32));
memory::set_bits(self.data_address, &self.pins.map(|pin| pin.pin as u32));
}
}
pub fn toggle_all(&mut self) {
unsafe {
memory::toggle_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32));
memory::toggle_bits(self.data_address, &self.pins.map(|pin| pin.pin as u32));
}
}
}
@@ -122,26 +110,26 @@ impl<const N: usize> WritablePins<N> {
#[derive(Clone, Copy)]
pub struct WritablePin {
data_address: *mut u32,
bit: Pin,
pin: Pin,
}
impl WritablePin {
pub fn read(&self) -> bool {
let current = unsafe { memory::read(self.data_address) };
current & (1 << self.bit as u32) != 0
current & (1 << self.pin as u32) != 0
}
pub fn clear(&mut self) {
unsafe {
memory::clear_bits(self.data_address, &[self.bit as u32]);
memory::clear_bits(self.data_address, &[self.pin as u32]);
}
}
pub fn set(&mut self) {
unsafe {
memory::set_bits(self.data_address, &[self.bit as u32]);
memory::set_bits(self.data_address, &[self.pin as u32]);
}
}
pub fn toggle(&mut self) {
unsafe {
memory::toggle_bits(self.data_address, &[self.bit as u32]);
memory::toggle_bits(self.data_address, &[self.pin as u32]);
}
}
}
@@ -149,6 +137,8 @@ impl WritablePin {
/// Page 684 of the data sheet for how the lock mechanism works
const UNLOCK: u32 = 0x4C4F434B;
/// TODO: read page 656 (10.3 Initialization and Configuration)
/// TODO: read page 657 (Table 10-3 GPIO Pad Configuration Examples)
fn setup_pins<const N: usize>(
port: Port,
pins: [Pin; N],
@@ -159,18 +149,6 @@ fn setup_pins<const N: usize>(
// Unlock the pins
unsafe {
memory::write(port.lock(), UNLOCK);
memory::set_bits(port.commit(), &pins_to_bits(&pins));
}
// Disable analog when it's not selected (and enable analog if it is)
match function {
Function::Analog => unsafe {
memory::set_bits(port.analog_mode_select(), &pins_to_bits(&pins));
},
_ => unsafe {
memory::clear_bits(port.analog_mode_select(), &pins_to_bits(&pins));
},
}
// Set to output pins if output (otherwise set to input)
@@ -184,27 +162,14 @@ fn setup_pins<const N: usize>(
}
}
let function_values = reverse_array(match function {
Function::Analog => todo!(),
Function::Digital => [L, L, L, L],
Function::CAN => [H, L, L, L],
Function::I2C => [L, L, H, H],
Function::PWM => [L, H, L, H],
Function::UART => [L, L, L, H],
});
for pin in pins {
let mut memory_bits = [0; 4];
let min = (pin as u32) * 4;
let max = min + 3;
let range = min..=max;
for (i, memory_bit) in range.enumerate() {
memory_bits[i] = memory_bit;
}
// Disable alternate function when it's not used (and enable it when it is)
if let Function::Analog | Function::Digital = function {
unsafe {
memory::write_bits(port.port_control(), &memory_bits, function_values);
memory::clear_bits(port.alternate_function_select(), &pins_to_bits(&pins));
}
} else {
unsafe {
memory::set_bits(port.alternate_function_select(), &pins_to_bits(&pins));
}
}
@@ -226,16 +191,9 @@ fn setup_pins<const N: usize>(
}
}
// TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states
// Disable alternate function when it's not used (and enable it when it is)
match function {
Function::Analog | Function::Digital => unsafe {
memory::clear_bits(port.alternate_function_select(), &pins_to_bits(&pins));
},
_ => unsafe {
memory::set_bits(port.alternate_function_select(), &pins_to_bits(&pins));
},
// TODO / WIP: commit here?!
unsafe {
memory::set_bits(port.commit(), &pins_to_bits(&pins));
}
// Enable digital function when it's needed (and disable it when it's not)
@@ -246,7 +204,53 @@ fn setup_pins<const N: usize>(
Function::Analog => unsafe {
memory::clear_bits(port.digital_enable(), &pins_to_bits(&pins));
},
_ => todo!(),
_ => todo!(), // and rewrite to if let when solved
}
// Enable analog when it's needed (and disable it when it's not)
if let Function::Analog = function {
unsafe {
memory::set_bits(port.analog_mode_select(), &pins_to_bits(&pins));
}
} else {
unsafe {
memory::clear_bits(port.analog_mode_select(), &pins_to_bits(&pins));
}
}
// Table 10-2 on page 650-651 of data sheet
let digital_function = match function {
Function::Analog => None,
Function::Digital => Some([L, L, L, L]),
Function::CAN => Some([H, L, L, L]),
Function::I2C => Some([L, L, H, H]),
Function::PWM => Some([L, H, L, H]),
Function::UART => Some([L, L, L, H]),
};
if let Some(array) = digital_function {
let port_control_values = reverse_array(array);
for pin in pins {
let mut memory_bits = [0; 4];
let min = (pin as u32) * 4;
let max = min + 3;
let range = min..=max;
for (i, memory_bit) in range.enumerate() {
memory_bits[i] = memory_bit;
}
unsafe {
memory::write_bits(port.port_control(), &memory_bits, port_control_values);
}
}
}
// TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states
// TODO / WIP: Re-lock the pins?!
unsafe {
memory::write(port.lock(), 0);
}
}
@@ -258,7 +262,7 @@ pub fn setup_readable_pins<const N: usize>(
setup_pins(port, pins, false, options.function, options.pull);
let data_address = port.data(&pins);
let pins: [ReadablePin; N] = pins.map(|bit| ReadablePin { data_address, bit });
let pins: [ReadablePin; N] = pins.map(|pin| ReadablePin { data_address, pin });
ReadablePins { data_address, pins }
}
@@ -270,9 +274,6 @@ pub fn setup_writable_pins<const N: usize>(
setup_pins(port, pins, true, options.function, Pull::Neither);
let data_address = port.data(&pins);
let pins: [WritablePin; N] = pins.map(|pin| WritablePin {
data_address,
bit: pin,
});
let pins: [WritablePin; N] = pins.map(|pin| WritablePin { data_address, pin });
WritablePins { data_address, pins }
}

View File

@@ -1,5 +1,5 @@
use crate::{
memory, registers, Pin, ReadablePinOptions, ReadablePins, WritablePinOptions, WritablePins,
memory, Board, Pin, ReadablePinOptions, ReadablePins, WritablePinOptions, WritablePins,
};
use super::pins::{setup_readable_pins, setup_writable_pins};
@@ -14,13 +14,13 @@ pub enum Port {
F,
}
pub struct PortOptions;
pub struct GPIOPortOptions;
impl Port {
/// The starting point of memory addresses corresponding to this GPIO register
///
/// Modeled after page 660 of data sheet (GPIO Register Map)
fn base(&self) -> u32 {
const fn base(&self) -> u32 {
match self {
Port::A => 0x4000_4000,
Port::B => 0x4000_5000,
@@ -34,7 +34,7 @@ impl Port {
/// The memory address of the alternate function select (AFSEL) register for this port
///
/// Page 671 of data sheet
pub(super) fn alternate_function_select(&self) -> *mut u32 {
pub(super) const fn alternate_function_select(&self) -> *mut u32 {
const OFFSET: u32 = 0x420;
(self.base() + OFFSET) as *mut u32
}
@@ -42,7 +42,7 @@ impl Port {
/// The memory address of the analog mode select (AMSEL) register for this port
///
/// Page 687 of data sheet
pub(super) fn analog_mode_select(&self) -> *mut u32 {
pub(super) const fn analog_mode_select(&self) -> *mut u32 {
const OFFSET: u32 = 0x52C;
(self.base() + OFFSET) as *mut u32
}
@@ -50,7 +50,7 @@ impl Port {
/// The memory address of the commit (CR) register for this port
///
/// Page 685 of data sheet
pub(super) fn commit(&self) -> *mut u32 {
pub(super) const fn commit(&self) -> *mut u32 {
const OFFSET: u32 = 0x524;
(self.base() + OFFSET) as *mut u32
}
@@ -76,7 +76,7 @@ impl Port {
/// The memory address of the digital enable (DEN) register for this port
///
/// Page 682 of data sheet
pub(super) fn digital_enable(&self) -> *mut u32 {
pub(super) const fn digital_enable(&self) -> *mut u32 {
const OFFSET: u32 = 0x51C;
(self.base() + OFFSET) as *mut u32
}
@@ -84,7 +84,7 @@ impl Port {
/// The memory address of the direction (DIR) register for this port
///
/// Page 663 of data sheet
pub(super) fn direction(&self) -> *mut u32 {
pub(super) const fn direction(&self) -> *mut u32 {
const OFFSET: u32 = 0x400;
(self.base() + OFFSET) as *mut u32
}
@@ -92,7 +92,7 @@ impl Port {
/// The memory address of the lock (LOCK) register
///
/// Page 684 of data sheet
pub(super) fn lock(&self) -> *mut u32 {
pub(super) const fn lock(&self) -> *mut u32 {
const OFFSET: u32 = 0x520;
(self.base() + OFFSET) as *mut u32
}
@@ -100,21 +100,21 @@ impl Port {
/// The memory address of the port control (PCTL) register for this port
///
/// Page 688 of data sheet
pub(super) fn port_control(&self) -> *mut u32 {
pub(super) const fn port_control(&self) -> *mut u32 {
const OFFSET: u32 = 0x52C;
(self.base() + OFFSET) as *mut u32
}
/// The memory address of the pull-down resistor select (PDR) register for this port
/// Page 679 of data sheet
pub(super) fn pull_down_select(&self) -> *mut u32 {
pub(super) const fn pull_down_select(&self) -> *mut u32 {
const OFFSET: u32 = 0x514;
(self.base() + OFFSET) as *mut u32
}
/// The memory address of the pull-up resistor select (PUR) register for this port
/// Page 677 of data sheet
pub(super) fn pull_up_select(&self) -> *mut u32 {
pub(super) const fn pull_up_select(&self) -> *mut u32 {
const OFFSET: u32 = 0x510;
(self.base() + OFFSET) as *mut u32
}
@@ -125,8 +125,8 @@ impl Port {
}
impl Port {
/// The corresponding bit for this port in system's run-mode clock gate control (RCGC) register
fn run_mode_clock_gate_control(&self) -> u32 {
/// The corresponding bit for this port in the system's GPIO Run mode clock gating control (RCGCGPIO) register
const fn run_mode_clock_gate_control(&self) -> u32 {
match self {
Port::A => 0,
Port::B => 1,
@@ -160,11 +160,12 @@ impl UsablePort {
}
}
pub fn setup_gpio_port(port: Port, _options: PortOptions) -> UsablePort {
// TODO: remove unused port setup options
pub fn setup_port(board: Board, port: Port, _options: GPIOPortOptions) -> UsablePort {
unsafe {
memory::set_bits(
registers::system::RCGCGPIO,
&[port.run_mode_clock_gate_control() as u32],
board.gpio_run_mode_clock_gate_control(),
&[port.run_mode_clock_gate_control()],
);
}

View File

@@ -2,9 +2,7 @@
use core::ptr;
use crate::L;
pub unsafe fn read(address: *mut u32) -> u32 {
pub unsafe fn read(address: *const u32) -> u32 {
ptr::read_volatile(address)
}
pub unsafe fn write(address: *mut u32, new: u32) {
@@ -15,29 +13,20 @@ pub unsafe fn update<Updater: Fn(u32) -> u32>(address: *mut u32, updater: Update
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 mut result = [L; N];
// TODO: look up accumulate or reduce or something
for (i, bit) in bits.iter().enumerate() {
result[i] = (current & (1 << bit)) != 0;
}
result
bits.map(|bit| current & (1 << bit) != 0)
}
pub unsafe fn write_bits<const N: usize>(address: *mut u32, bits: &[u32; N], values: [bool; N]) {
update(address, |current| {
let mut new = current;
// TODO: look up accumulate or reduce or something
for (bit, set) in bits.iter().zip(values) {
bits.iter().zip(values).fold(current, |result, (bit, set)| {
if set {
new |= 1 << bit;
result | (1 << bit)
} else {
new &= !(1 << bit);
result & !(1 << bit)
}
}
new
})
})
}
@@ -51,37 +40,17 @@ pub unsafe fn update_bits<Updater: Fn([bool; N]) -> [bool; N], const N: usize>(
pub unsafe fn set_bits(address: *mut u32, bits: &[u32]) {
update(address, |current| {
let mut new = current;
// TODO: look up accumulate or reduce or something
for bit in bits {
new |= 1 << bit;
}
new
bits.iter().fold(current, |result, bit| result | (1 << bit))
})
}
pub unsafe fn clear_bits(address: *mut u32, bits: &[u32]) {
update(address, |current| {
let mut new = current;
// TODO: look up accumulate or reduce or something
for bit in bits {
new &= !(1 << bit);
}
new
bits.iter()
.fold(current, |result, bit| result & !(1 << bit))
})
}
pub unsafe fn toggle_bits(address: *mut u32, bits: &[u32]) {
update(address, |current| {
let mut new = current;
// TODO: look up accumulate or reduce or something
for bit in bits {
new ^= 1 << bit;
}
new
bits.iter().fold(current, |result, bit| result ^ (1 << bit))
})
}

View File

@@ -3,7 +3,8 @@
mod board;
mod gpio;
mod memory;
mod registers;
mod uart;
mod utils;
pub use board::*;
pub use gpio::pins::*;

View File

@@ -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
View 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
View 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
}

View File

@@ -54,7 +54,8 @@ static HEAP: BumpPointerAlloc = BumpPointerAlloc {
end: 0x2000_0200,
};
#[macro_use]
// TODO: remove or fix
// #[macro_use]
extern crate alloc;
use alloc::string::String;
@@ -63,39 +64,31 @@ use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch
use cortex_m_rt::entry;
use driver_and_task_library::{
setup_board, Function, Pin, Port, PortOptions, ReadablePinOptions, UsableBoard,
WritablePinOptions, H, L, Pull,
setup_board, Function, GPIOPortOptions, Pin, Port, Pull, ReadablePinOptions,
WritablePinOptions, H, L,
};
const SYSCTL_RCGC1_R: *mut u32 = 0x400FE104 as *mut u32;
const SYSCTL_RCGC2_R: *mut u32 = 0x400FE108 as *mut u32;
/// UART0 data register
const UART0_DR_R: *mut u32 = 0x4000C000 as *mut u32;
/// UART0 flag register
const UART0_FR_R: *mut u32 = 0x4000C018 as *mut u32;
/// UART0 integer baud rate register
const UART0_IBRD_R: *mut u32 = 0x4000C024 as *mut u32;
/// UART0 fractional baud rate register
const UART0_FBRD_R: *mut u32 = 0x4000C028 as *mut u32;
/// UART0 line control register
const UART0_LCRH_R: *mut u32 = 0x4000C02C as *mut u32;
/// UART0 control register
const UART0_CTL_R: *mut u32 = 0x4000C030 as *mut u32;
const GPIO_PORTA_AFSEL_R: *mut u32 = 0x40004420 as *mut u32;
const GPIO_PORTA_DEN_R: *mut u32 = 0x4000451C as *mut u32;
// page 219
/// 16 MHz
const SYSTEM_OSC_CLOCK_SPEED: u32 = 16_000_000;
// the MOSC is variable frequeny (5 MHz to 25 MHz)
// the XOSC can act as a real time clock as well!
// The internal system clock (SysClk), is derived from any of the above sources plus two others: the
// output of the main internal PLL and the precision internal oscillator divided by four (4 MHz ± 1%).
// The frequency of the PLL clock reference must be in the range of 5 MHz to 25 MHz (inclusive).
// Table 5-3 on page 220 shows how the various clock sources can be used in a system
/// UART0 Clock Gating Control
const SYSCTL_RCGC1_UART0: u32 = 0x00000001;
/// port A Clock Gating Control
const SYSCTL_RCGC2_GPIOA: u32 = 0x00000001;
/// UART Enable
const UART_CTL_UARTEN: u32 = 0x00000001;
/// 8 bit word length
@@ -109,18 +102,21 @@ const UART_FR_RXFE: u32 = 0x00000010;
/// Pins 0 and 1
const PINS_0_AND_1: u32 = 0b0000_0011;
fn uart0_init(board: &mut UsableBoard) {
fn uart0_init() {
unsafe {
// activate UART0
ptr::write_volatile(
SYSCTL_RCGC1_R,
ptr::read_volatile(SYSCTL_RCGC1_R) | SYSCTL_RCGC1_UART0,
);
// write_color(MAGENTA);
// activate port A
// ptr::write_volatile(SYSCTL_RCGC2_R, ptr::read_volatile(SYSCTL_RCGC2_R) | SYSCTL_RCGC2_GPIOA);
// ^ commented in favor of v
board.setup_gpio_port(Port::A, PortOptions);
// For some reason, 7 no-ops are needed to stall the CPU while UART is enabled
for _ in 0..7 {
asm!("nop");
}
// TODO / WIP: done up to here
// disable UART while setting it up
ptr::write_volatile(
@@ -128,7 +124,6 @@ fn uart0_init(board: &mut UsableBoard) {
ptr::read_volatile(UART0_CTL_R) & !UART_CTL_UARTEN,
);
// ignore: // IBRD = int(50,000,000 / (16 * 115,200)) = int(27.1267)
// IBRD = int(16,000,000 / (16 * 115,200)) = int(8.680)
// ptr::write_volatile(UART0_IBRD_R, 8);
ptr::write_volatile(UART0_IBRD_R, 8);
@@ -140,8 +135,7 @@ fn uart0_init(board: &mut UsableBoard) {
// 8 bit word length (no parity bits, one stop bit, FIFOs)
// ptr::write_volatile(UART0_LCRH_R, UART_LCRH_WLEN_8|UART_LCRH_FEN);
// 8 bit word length (no parity bits, one stop bit, no FIFOs)
ptr::write_volatile(UART0_LCRH_R, UART_LCRH_WLEN_8 & !UART_LCRH_FEN);
ptr::write_volatile(UART0_LCRH_R, UART_LCRH_WLEN_8 | UART_LCRH_FEN);
// enable UART since it's been set up
ptr::write_volatile(
@@ -162,7 +156,7 @@ fn uart0_init(board: &mut UsableBoard) {
}
}
fn uart0_out_char(c: u8) {
fn uart0_out_char_blocking(c: u8) {
loop {
let fr = unsafe { ptr::read_volatile(UART0_FR_R) };
@@ -176,12 +170,24 @@ fn uart0_out_char(c: u8) {
}
}
fn uart0_out_string(s: &str) {
fn uart0_out_string_blocking(s: &str) {
for c in s.bytes() {
uart0_out_char(c);
uart0_out_char_blocking(c);
}
}
fn uart0_in_char_blocking() -> u8 {
loop {
let fr = unsafe { ptr::read_volatile(UART0_FR_R) };
if (fr & UART_FR_RXFE) == 0 {
break;
}
}
unsafe { ptr::read_volatile(UART0_DR_R) as u8 }
}
const WHITE: [bool; 3] = [H, H, H];
const BLACK: [bool; 3] = [L, L, L];
@@ -195,25 +201,8 @@ const MAGENTA: [bool; 3] = [H, L, H];
#[entry]
fn main() -> ! {
let mut board = setup_board();
let mut port_a = board.setup_gpio_port(Port::A, PortOptions);
let mut port_f = board.setup_gpio_port(Port::F, PortOptions);
uart0_init(&mut board);
// WIP: page 682
port_a.setup_writable_pins(
[Pin::One],
WritablePinOptions {
function: Function::UART,
},
);
uart0_out_string("Hi, this is after uart setup_writable_pins\r\n\r\n");
// TODO: finish this
// port_a.setup_readable_pins([Pin::Zero], WritablePinOptions {
// function: Function::UART,
// });
// uart0_out_string("Hi, this is after uart setup_readable_pins\r\n\r\n");
let mut port_a = board.setup_gpio_port(Port::A, GPIOPortOptions);
let mut port_f = board.setup_gpio_port(Port::F, GPIOPortOptions);
let switches = port_f.setup_readable_pins(
[Pin::Zero, Pin::Four],
@@ -222,8 +211,6 @@ fn main() -> ! {
pull: Pull::Up,
},
);
let [_sw1, _sw2] = switches.pins();
let mut rgb_led = port_f.setup_writable_pins(
[Pin::One, Pin::Three, Pin::Two],
WritablePinOptions {
@@ -231,18 +218,33 @@ fn main() -> ! {
},
);
// TODO: finish this
uart0_init();
// WIP: page 682
port_a.setup_writable_pins(
[Pin::One],
WritablePinOptions {
function: Function::UART,
},
);
uart0_out_string_blocking("Hi, this is after!! uart setup_writable_pins\r\n\r\n");
port_a.setup_readable_pins(
[Pin::Zero],
ReadablePinOptions {
function: Function::UART,
pull: Pull::Neither,
},
);
uart0_out_string_blocking("Hi, this is after uart setup_readable_pins\r\n\r\n");
let rainbow = [RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA];
// TODO: WIP: debugging
// let s = format!("Rainbow: {:?}\r\n", rainbow);
let s = String::from("\r\ntesting a static string!!!\r\n\r\n\r\n");
// let s = format!("Format");
// let s: String = rainbow.into();
uart0_out_string(&s);
uart0_out_string_blocking(&s);
loop {
uart0_out_string("Hi the program is still running down here!\r\n");
// uart0_out_string_blocking("Hi still running down here!\r\n");
match switches.read_all() {
[L, L] => rgb_led.write_all(WHITE),
[L, H] => rgb_led.write_all(BLUE),
@@ -252,10 +254,15 @@ fn main() -> ! {
// uart0_out_string(&format!("The switches read {:?}", switches.read_all()));
for _ in 0..1000000 {
unsafe {
asm!("nop");
}
}
// for _ in 0..1000000 {
// unsafe {
// asm!("nop");
// }
// }
let new_char = uart0_in_char_blocking();
uart0_out_string_blocking("New character received: ");
uart0_out_char_blocking(new_char);
uart0_out_string_blocking("\r\n");
}
}