@ -23,28 +23,116 @@
* /
use super ::MMIO_BASE ;
use core ::ops ;
use core ::sync ::atomic ::{ compiler_fence , Ordering } ;
use core ::{
ops ,
sync ::atomic ::{ compiler_fence , Ordering } ,
} ;
use gpio ;
use mbox ;
use volatile_register ::* ;
use register ::mmio ::* ;
// PL011 UART registers.
//
// Descriptions taken from
// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf
register_bitfields ! {
u32 ,
/// Flag Register
FR [
/// Transmit FIFO full. The meaning of this bit depends on the
/// state of the FEN bit in the UARTLCR_ LCRH Register. If the
/// FIFO is disabled, this bit is set when the transmit
/// holding register is full. If the FIFO is enabled, the TXFF
/// bit is set when the transmit FIFO is full.
TXFF OFFSET ( 5 ) NUMBITS ( 1 ) [ ] ,
/// Receive FIFO empty. The meaning of this bit depends on the
/// state of the FEN bit in the UARTLCR_H Register. If the
/// FIFO is disabled, this bit is set when the receive holding
/// register is empty. If the FIFO is enabled, the RXFE bit is
/// set when the receive FIFO is empty.
RXFE OFFSET ( 4 ) NUMBITS ( 1 ) [ ]
] ,
/// Integer Baud rate divisor
IBRD [
/// Integer Baud rate divisor
IBRD OFFSET ( 0 ) NUMBITS ( 16 ) [ ]
] ,
/// Fractional Baud rate divisor
FBRD [
/// Fractional Baud rate divisor
FBRD OFFSET ( 0 ) NUMBITS ( 6 ) [ ]
] ,
/// Line Control register
LCRH [
/// Word length. These bits indicate the number of data bits
/// transmitted or received in a frame.
WLEN OFFSET ( 5 ) NUMBITS ( 2 ) [
FiveBit = 0b00 ,
SixBit = 0b01 ,
SevenBit = 0b10 ,
EightBit = 0b11
]
] ,
/// Control Register
CR [
/// Receive enable. If this bit is set to 1, the receive
/// section of the UART is enabled. Data reception occurs for
/// UART signals. When the UART is disabled in the middle of
/// reception, it completes the current character before
/// stopping.
RXE OFFSET ( 9 ) NUMBITS ( 1 ) [
Disabled = 0 ,
Enabled = 1
] ,
/// Transmit enable. If this bit is set to 1, the transmit
/// section of the UART is enabled. Data transmission occurs
/// for UART signals. When the UART is disabled in the middle
/// of transmission, it completes the current character before
/// stopping.
TXE OFFSET ( 8 ) NUMBITS ( 1 ) [
Disabled = 0 ,
Enabled = 1
] ,
/// UART enable
UARTEN OFFSET ( 0 ) NUMBITS ( 1 ) [
/// If the UART is disabled in the middle of transmission
/// or reception, it completes the current character
/// before stopping.
Disabled = 0 ,
Enabled = 1
]
] ,
/// Interupt Clear Register
ICR [
/// Meta field for all pending interrupts
ALL OFFSET ( 0 ) NUMBITS ( 11 ) [ ]
]
}
const UART_BASE : u32 = MMIO_BASE + 0x20_1000 ;
// PL011 UART registers
#[ allow(non_snake_case) ]
#[ repr(C) ]
pub struct RegisterBlock {
DR : RW < u32 > , // 0x00
DR : R ead Write < u32 > , // 0x00
__reserved_0 : [ u32 ; 5 ] , // 0x04
FR : RO < u32 > , // 0x18
FR : R ead Only < u32 , FR ::Register > , // 0x18
__reserved_1 : [ u32 ; 2 ] , // 0x1c
IBRD : WO < u32 > , // 0x24
FBRD : WO < u32 > , // 0x28
LCRH : WO < u32 > , // 0x2C
CR : WO < u32 > , // 0x30
IBRD : W rite Only < u32 , IBRD ::Register > , // 0x24
FBRD : W rite Only < u32 , FBRD ::Register > , // 0x28
LCRH : W rite Only < u32 , LCRH ::Register > , // 0x2C
CR : W rite Only < u32 , CR ::Register > , // 0x30
__reserved_2 : [ u32 ; 4 ] , // 0x34
ICR : WO < u32 > , // 0x44
ICR : W rite Only < u32 , ICR ::Register > , // 0x44
}
pub enum UartError {
@ -75,7 +163,7 @@ impl Uart {
///Set baud rate and characteristics (115200 8N1) and map to GPIO
pub fn init ( & self , mbox : & mut mbox ::Mbox ) -> Result < ( ) > {
// turn off UART0
unsafe { self . CR . write ( 0 ) } ;
self . CR . set ( 0 ) ;
// set up clock for consistent divisor values
mbox . buffer [ 0 ] = 9 * 4 ;
@ -99,33 +187,30 @@ impl Uart {
// map UART0 to GPIO pins
unsafe {
( * gpio ::GPFSEL1 ) . modify ( | x | {
// Modify with a closure
let mut ret = x ;
ret & = ! ( ( 7 < < 12 ) | ( 7 < < 15 ) ) ; // gpio14, gpio15
ret | = ( 4 < < 12 ) | ( 4 < < 15 ) ; // alt0
( * gpio ::GPFSEL1 ) . modify ( gpio ::GPFSEL1 ::FSEL14 ::TXD0 + gpio ::GPFSEL1 ::FSEL15 ::RXD0 ) ;
ret
} ) ;
( * gpio ::GPPUD ) . write ( 0 ) ; // enable pins 14 and 15
( * gpio ::GPPUD ) . set ( 0 ) ; // enable pins 14 and 15
for _ in 0 .. 150 {
asm! ( "nop" :::: "volatile" ) ;
}
( * gpio ::GPPUDCLK0 ) . write ( ( 1 < < 14 ) | ( 1 < < 15 ) ) ;
( * gpio ::GPPUDCLK0 ) . write (
gpio ::GPPUDCLK0 ::PUDCLK14 ::AssertClock + gpio ::GPPUDCLK0 ::PUDCLK15 ::AssertClock ,
) ;
for _ in 0 .. 150 {
asm! ( "nop" :::: "volatile" ) ;
}
( * gpio ::GPPUDCLK0 ) . write ( 0 ) ;
self . ICR . write ( 0x7FF ) ; // clear interrupts
self . IBRD . write ( 2 ) ; // 115200 baud
self . FBRD . write ( 0xB ) ;
self . LCRH . write ( 0b11 < < 5 ) ; // 8n1
self . CR . write ( 0x301 ) ; // enable Tx, Rx, FIFO
( * gpio ::GPPUDCLK0 ) . set ( 0 ) ;
}
self . ICR . write ( ICR ::ALL ::CLEAR ) ;
self . IBRD . write ( IBRD ::IBRD . val ( 2 ) ) ; // Results in 115200 baud
self . FBRD . write ( FBRD ::FBRD . val ( 0xB ) ) ;
self . LCRH . write ( LCRH ::WLEN ::EightBit ) ; // 8N1
self . CR
. write ( CR ::UARTEN ::Enabled + CR ::TXE ::Enabled + CR ::RXE ::Enabled ) ;
Ok ( ( ) )
}
@ -133,7 +218,7 @@ impl Uart {
pub fn send ( & self , c : char ) {
// wait until we can send
loop {
if ( self . FR . read ( ) & 0x20 ) ! = 0x20 {
if ! self . FR . is_set ( FR ::TXFF ) {
break ;
}
@ -141,14 +226,14 @@ impl Uart {
}
// write the character to the buffer
unsafe { self . DR . write ( c as u32 ) } ;
self . DR . set ( c as u32 ) ;
}
/// Receive a character
pub fn getc ( & self ) -> char {
// wait until something is in the buffer
loop {
if ( self . FR . read ( ) & 0x10 ) ! = 0x10 {
if ! self . FR . is_set ( FR ::RXFE ) {
break ;
}
@ -156,7 +241,7 @@ impl Uart {
}
// read it and return
let mut ret = self . DR . read ( ) as u8 as char ;
let mut ret = self . DR . get ( ) as u8 as char ;
// convert carrige return to newline
if ret = = '\r' {