Created
May 23, 2017 21:25
-
-
Save thejpster/d5605e6e8e168657a414bfb1ffcad53e to your computer and use it in GitHub Desktop.
UART driver doesn't work
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! # UART for the LM4F120H5QR | |
// **************************************************************************** | |
// | |
// Imports | |
// | |
// **************************************************************************** | |
use core::fmt; | |
use core::intrinsics::{volatile_load, volatile_store}; | |
use embedded_serial::{self, BlockingTx, NonBlockingRx}; | |
use cortex_m::asm::nop; | |
use super::gpio; | |
use super::pll; | |
use super::registers as reg; | |
use tm4c123x::uart0; | |
// **************************************************************************** | |
// | |
// Public Types | |
// | |
// **************************************************************************** | |
/// This chip has 8 UARTs | |
#[derive(PartialEq, Clone, Copy)] | |
#[allow(missing_docs)] | |
pub enum UartId { | |
Uart0, | |
Uart1, | |
Uart2, | |
Uart3, | |
Uart4, | |
Uart5, | |
Uart6, | |
Uart7, | |
} | |
/// Controls a single UART | |
/// Only supports 8/N/1 - who needs anything else? | |
pub struct Uart { | |
id: UartId, | |
baud: u32, | |
nl_mode: NewlineMode, | |
reg: &'static mut reg::UartRegisters, | |
reg2: &'static mut uart0::RegisterBlock, | |
} | |
/// writeln!() emits LF chars, so this is useful | |
/// if you're writing text with your UART | |
#[derive(PartialEq, Clone, Copy)] | |
pub enum NewlineMode { | |
/// Emit octets as received | |
Binary, | |
/// Emit an extra CR before every LF | |
SwapLFtoCRLF, | |
} | |
// **************************************************************************** | |
// | |
// Private Types | |
// | |
// **************************************************************************** | |
// None | |
// **************************************************************************** | |
// | |
// Public Data | |
// | |
// **************************************************************************** | |
// None | |
// **************************************************************************** | |
// | |
// Public Functions | |
// | |
// **************************************************************************** | |
/// Represents a single UART on the LM4F120 | |
impl Uart { | |
/// Create a new Uart object. The caller is responsible for ensuring | |
/// that only one object exists per UartId. The UART is set to | |
/// 8 data bits, 1 stop bit, no parity and is not configurable. | |
/// Optionally, newline translation can be performed on outbound data | |
/// - this will cause writeln!() to emit a CRLF. | |
pub fn new(id: UartId, baud: u32, nl_mode: NewlineMode) -> Uart { | |
let mut uart = Uart { | |
id: id, | |
baud: baud, | |
nl_mode: nl_mode, | |
reg: get_uart_registers(id), | |
reg2: get_uart_registers2(id), | |
}; | |
uart.init(); | |
uart | |
} | |
/// Configure the hardware | |
fn init(&mut self) -> () { | |
// Do GPIO pin muxing | |
gpio::enable_uart(self.id); | |
// Enable UART module in RCGUART register p306 | |
unsafe { | |
self.enable_clock(); | |
// Disable UART and all features | |
self.reg2.ctl.reset(); | |
// Calculate the baud rate values | |
// baud_div = CLOCK_RATE / (16 * baud_rate); | |
// baud_int = round(baud_div * 64) | |
let baud_int: u32 = (((pll::get_clock_hz() * 8) / self.baud) + 1) / 2; | |
// Store the upper and lower parts of the divider | |
self.reg.ibrd.write((baud_int / 64) as usize); | |
self.reg.fbrd.write((baud_int % 64) as usize); | |
// Set the UART Line Control register value | |
// 8N1 + FIFO enabled | |
self.reg.lcrh.write(reg::UART_LCRH_WLEN_8 | reg::UART_LCRH_FEN); | |
// Clear the flags | |
self.reg.rf.write(0); | |
// Enable | |
self.reg.ctl.write(reg::UART_CTL_RXE | reg::UART_CTL_TXE | reg::UART_CTL_UARTEN); | |
} | |
} | |
/// Select which bits to enable in the clock gating register | |
fn get_clock_gating_mask(&self) -> usize { | |
match self.id { | |
UartId::Uart0 => reg::SYSCTL_RCGCUART_R0, | |
UartId::Uart1 => reg::SYSCTL_RCGCUART_R1, | |
UartId::Uart2 => reg::SYSCTL_RCGCUART_R2, | |
UartId::Uart3 => reg::SYSCTL_RCGCUART_R3, | |
UartId::Uart4 => reg::SYSCTL_RCGCUART_R4, | |
UartId::Uart5 => reg::SYSCTL_RCGCUART_R5, | |
UartId::Uart6 => reg::SYSCTL_RCGCUART_R6, | |
UartId::Uart7 => reg::SYSCTL_RCGCUART_R7, | |
} | |
} | |
/// Enable the module in the real-time clock gating registers. | |
unsafe fn enable_clock(&mut self) { | |
volatile_store(reg::SYSCTL_RCGCUART_R, self.get_clock_gating_mask()); | |
while volatile_load(reg::SYSCTL_RCGCUART_R) != self.get_clock_gating_mask() { | |
nop(); | |
} | |
} | |
#[deprecated] | |
pub fn read_single(&mut self) -> Option<u8> { | |
self.getc_try().unwrap() | |
} | |
} | |
impl embedded_serial::BlockingTx for Uart { | |
type Error = !; | |
/// Emit a single octet, busy-waiting if the FIFO is full. | |
/// Never returns `Err`. | |
fn putc(&mut self, value: u8) -> Result<(), Self::Error>{ | |
while (self.reg.rf.read() & reg::UART_FR_TXFF) != 0 { | |
nop(); | |
} | |
self.reg.data.write(value as usize); | |
Ok(()) | |
} | |
} | |
impl embedded_serial::NonBlockingTx for Uart { | |
type Error = !; | |
/// Attempts to write to the UART. Returns `Ok(None)` if the transmiter | |
/// not ready, or `Ok(Some(value))`. Never returns `Err`. | |
fn putc_try(&mut self, value: u8) -> Result<Option<u8>, Self::Error>{ | |
if (self.reg.rf.read() & reg::UART_FR_TXFF) != 0 { | |
Ok(None) | |
} else { | |
self.reg.data.write(value as usize); | |
Ok(Some(value)) | |
} | |
} | |
} | |
impl embedded_serial::BlockingRx for Uart { | |
type Error = !; | |
/// Read a single octet, busy-waiting if the FIFO is empty. | |
/// Never returns `Err`. | |
fn getc(&mut self) -> Result<u8, Self::Error> { | |
while (self.reg.rf.read() & reg::UART_FR_RXFE) != 0 { | |
nop(); | |
} | |
Ok(self.reg.data.read() as u8) | |
} | |
} | |
impl embedded_serial::NonBlockingRx for Uart { | |
type Error = !; | |
/// Attempts to read from the UART. Returns `Ok(None)` if the FIFO is | |
/// empty, or `Ok(octet)`. Never returns `Err`. | |
fn getc_try(&mut self) -> Result<Option<u8>, Self::Error> { | |
if (self.reg.rf.read() & reg::UART_FR_RXFE) != 0 { | |
Ok(None) | |
} else { | |
Ok(Some(self.reg.data.read() as u8)) | |
} | |
} | |
} | |
/// Allows the Uart to be passed to 'write!()' and friends. | |
impl fmt::Write for Uart { | |
fn write_str(&mut self, s: &str) -> fmt::Result { | |
match self.nl_mode { | |
NewlineMode::Binary => { | |
self.puts(s).unwrap() | |
} | |
NewlineMode::SwapLFtoCRLF => { | |
for byte in s.bytes() { | |
if byte == 0x0A { | |
// Prefix every \n with a \r | |
self.putc(0x0D).unwrap() | |
} | |
self.putc(byte).unwrap() | |
} | |
} | |
} | |
Ok(()) | |
} | |
} | |
/// Called when UART 0 interrupt fires | |
pub unsafe extern "C" fn uart0_isr() {} | |
// **************************************************************************** | |
// | |
// Private Functions | |
// | |
// **************************************************************************** | |
/// Get a reference to the UART control register struct in the chip. | |
fn get_uart_registers(uart_id: UartId) -> &'static mut reg::UartRegisters { | |
unsafe { | |
match uart_id { | |
UartId::Uart0 => &mut *(reg::UART0_DR_R as *mut reg::UartRegisters), | |
UartId::Uart1 => &mut *(reg::UART1_DR_R as *mut reg::UartRegisters), | |
UartId::Uart2 => &mut *(reg::UART2_DR_R as *mut reg::UartRegisters), | |
UartId::Uart3 => &mut *(reg::UART3_DR_R as *mut reg::UartRegisters), | |
UartId::Uart4 => &mut *(reg::UART4_DR_R as *mut reg::UartRegisters), | |
UartId::Uart5 => &mut *(reg::UART5_DR_R as *mut reg::UartRegisters), | |
UartId::Uart6 => &mut *(reg::UART6_DR_R as *mut reg::UartRegisters), | |
UartId::Uart7 => &mut *(reg::UART7_DR_R as *mut reg::UartRegisters), | |
} | |
} | |
} | |
/// Get a reference to the UART control register struct in the chip. | |
fn get_uart_registers2(uart_id: UartId) -> &'static mut uart0::RegisterBlock { | |
use tm4c123x::{UART0, UART1, UART2, UART3, UART4, UART5, UART6, UART7}; | |
unsafe { | |
match uart_id { | |
UartId::Uart0 => &mut *UART0.get(), | |
UartId::Uart1 => &mut *UART1.get(), | |
UartId::Uart2 => &mut *UART2.get(), | |
UartId::Uart3 => &mut *UART3.get(), | |
UartId::Uart4 => &mut *UART4.get(), | |
UartId::Uart5 => &mut *UART5.get(), | |
UartId::Uart6 => &mut *UART6.get(), | |
UartId::Uart7 => &mut *UART7.get(), | |
} | |
} | |
} | |
// **************************************************************************** | |
// | |
// End Of File | |
// | |
// **************************************************************************** |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment