From: Tilman Sauerbeck Date: Sat, 28 Dec 2019 18:54:46 +0000 (+0100) Subject: common: Add the uart module. X-Git-Url: http://git.code-monkey.de/?a=commitdiff_plain;h=9ea07b3d30e9405cd51a48e5af4e40ae27b17ca6;p=gps-watch.git common: Add the uart module. --- diff --git a/SConscript.libcommon b/SConscript.libcommon index d353e61..e1d378c 100644 --- a/SConscript.libcommon +++ b/SConscript.libcommon @@ -10,6 +10,7 @@ source_files_rs = [ 'src/common/port.rs', 'src/common/gpio.rs', 'src/common/i2c.rs', + 'src/common/uart.rs', 'src/common/watchdog.rs', 'src/common/crc32.rs', 'src/common/buffer.rs', diff --git a/src/common/lib.rs b/src/common/lib.rs index b6a08c7..61d8f79 100644 --- a/src/common/lib.rs +++ b/src/common/lib.rs @@ -32,6 +32,7 @@ pub mod systick; pub mod port; pub mod gpio; pub mod i2c; +pub mod uart; pub mod watchdog; pub mod crc32; pub mod buffer; diff --git a/src/common/uart.rs b/src/common/uart.rs new file mode 100644 index 0000000..98a0c51 --- /dev/null +++ b/src/common/uart.rs @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2019 Tilman Sauerbeck (tilman at code-monkey de) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +use register; + +type Reg8 = register::Register; +type Reg32 = register::Register; + +const UART_BASE: u32 = 0x4006a000; + +pub const UART0: u32 = UART_BASE + 0x0000; +pub const UART1: u32 = UART_BASE + 0x1000; +pub const UART2: u32 = UART_BASE + 0x2000; + +const SIM_BASE : u32 = 0x40047000; + +const SIM_SOPT2: u32 = SIM_BASE + 0x1004; +const SIM_SCGC4: u32 = SIM_BASE + 0x1034; + +const SIM_SOPT2_UART0SRC_SHIFT: u32 = 26; + +const SIM_SCGC4_UART0: u32 = 1 << 10; +const SIM_SCGC4_UART1: u32 = 1 << 11; +const SIM_SCGC4_UART2: u32 = 1 << 12; + +const UART_BDH: u32 = 0x00; +const UART_BDL: u32 = 0x01; +const UART_C2 : u32 = 0x03; +const UART_S1 : u32 = 0x04; +const UART_D : u32 = 0x07; +const UART_C4 : u32 = 0x0a; +const UART_C5 : u32 = 0x0b; + +const UART_S1_RDRF: u8 = 1 << 5; + +const UART_C2_RE : u8 = 1 << 2; +const UART_C2_TE : u8 = 1 << 3; +const UART_C2_RIE : u8 = 1 << 5; + +const UART_C4_OSR_SHIFT: u32 = 0; +const UART_C4_OSR_MASK : u8 = 0xf << UART_C4_OSR_SHIFT; + +const UART_C5_BOTHEDGE : u8 = 1 << 1; + +pub fn configure(uart: u32) { + Reg32::new(SIM_SOPT2).modify(|v| { + let mut m = v; + + m &= !(3 << SIM_SOPT2_UART0SRC_SHIFT); + m |= 2 << SIM_SOPT2_UART0SRC_SHIFT; + + m + }); + + Reg32::new(SIM_SCGC4).modify(|v| { + if uart == UART0 { + v | SIM_SCGC4_UART0 + } else if uart == UART1 { + v | SIM_SCGC4_UART1 + } else if uart == UART2 { + v | SIM_SCGC4_UART2 + } else { + v + } + }); + + // Before we may mess with the baud rate, we need to disable + // both the receiver and the transmitter. + Reg8::new(uart + UART_C2).modify(|v| v & !(UART_C2_RE | UART_C2_TE)); + + // Set baud rate. + Reg8::new(uart + UART_BDH).write(0x0); + Reg8::new(uart + UART_BDL).write(0x34); + + // Configure minimum oversampling ratio. + Reg8::new(uart + UART_C4).modify(|v| { + let mut m = v; + + m &= !UART_C4_OSR_MASK; + m |= 3 << UART_C4_OSR_SHIFT; + + m + }); + + Reg8::new(uart + UART_C5).modify(|v| v | UART_C5_BOTHEDGE); + + // Enable receiver only (including interrupt). + Reg8::new(uart + UART_C2).write(UART_C2_RE | UART_C2_RIE); + + // XXX: + // Is this needed? + Reg8::new(uart + UART_S1).write(0xf); // Clear errors. +} + +pub fn try_read(uart: u32) -> Option { + let mut uart_s1 = Reg8::new(uart + UART_S1); + + let s1 = uart_s1.read(); + + let result = if (s1 & UART_S1_RDRF) == 0 { + None + } else { + Some(Reg8::new(uart + UART_D).read()) + }; + + let set_error_flags = s1 & 0x1f; + + // Acknowledge errors. + if set_error_flags != 0 { + uart_s1.write(set_error_flags); + } + + result +}