Skip to content
This repository has been archived by the owner on Jul 6, 2019. It is now read-only.

Commit

Permalink
k20::uart: Port to ioregs!
Browse files Browse the repository at this point in the history
  • Loading branch information
bgamari committed Aug 18, 2014
1 parent 103d4af commit 7c10b28
Showing 1 changed file with 199 additions and 80 deletions.
279 changes: 199 additions & 80 deletions src/hal/k20/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,6 @@ pub struct UART {
reg: &'static reg::UART,
}

/// UART word length.
#[allow(missing_doc)]
pub enum WordLen {
WordLen8bits = 0,
WordLen9bits = 0b00010000,
}

impl WordLen {
/// Convert from number to WordLen.
pub fn from_u8(val: u8) -> WordLen {
match val {
8 => WordLen8bits,
9 => WordLen9bits,
_ => unsafe { abort() },
}
}
}

/// Stop bits configuration.
/// K20 UART only supports one stop bit.
pub enum StopBit {
Expand All @@ -73,16 +55,6 @@ impl StopBit {
}
}

enum ParityEnabled {
PEDisabled = 0b00,
PEEnabled = 0b10,
}

enum ParitySelect {
PSOdd = 0b1,
PSEven = 0b0,
}

impl UARTPeripheral {
fn reg(self) -> &'static reg::UART {
match self {
Expand All @@ -101,8 +73,7 @@ impl UART {
reg: peripheral.reg()
};
uart.set_baud_rate(baudrate);
uart.set_mode(WordLen::from_u8(word_len), parity,
StopBit::from_u8(stop_bits));
uart.set_mode(reg::UART_c1_m::from_u8(word_len), parity, StopBit::from_u8(stop_bits));
uart.set_fifo_enabled(true);

uart
Expand All @@ -117,76 +88,224 @@ impl UART {
fn set_baud_rate(&self, baud_rate: u32) {
let sbr: u32 = self.uart_clock() / 16 / baud_rate;
let brfa: u32 = (2 * self.uart_clock() / baud_rate) % 32;
(*self.reg).set_BDH((sbr >> 8) as u8);
(*self.reg).set_BDL((sbr & 0xff) as u8);
(*self.reg).set_C4(((*self.reg).C4() & !0b11111) | brfa as u8);
(*self.reg).bdh.set_sbr((sbr >> 8) as u8);
(*self.reg).bdl.set_sbr((sbr & 0xff) as u8);
(*self.reg).c4.set_brfa(brfa as u8);
}

#[no_split_stack]
fn set_mode(&self, word_len: WordLen, parity: uart::Parity, _: StopBit) {
let c1: u8 = (*(self.reg)).C1();
let computed_val: u8 = word_len as u8 | match parity {
uart::Disabled => PEDisabled as u8 | PSOdd as u8,
uart::Odd => PEEnabled as u8 | PSOdd as u8,
uart::Even => PEEnabled as u8 | PSEven as u8,
fn set_mode(&self, word_len: reg::UART_c1_m, parity: uart::Parity,
_stop_bits: StopBit) {
let mut c1 = (*self.reg).c1.set_m(word_len);
match parity {
uart::Disabled => {c1.set_pe(false);}
uart::Odd => {c1.set_pe(true).set_pt(reg::Odd);}
uart::Even => {c1.set_pe(true).set_pt(reg::Even);}
uart::Forced1 => unsafe { abort() },
uart::Forced0 => unsafe { abort() },
};
let new_c1 = (c1 & !0x3) | computed_val;

(*(self.reg)).set_C1(new_c1);
}

fn set_fifo_enabled(&self, enabled: bool) {
let val: u8 = match enabled {
true => PFIFOTxFifoEnabled | PFIFORxFifoEnabled,
false => 0,
};

(*(self.reg)).set_PFIFO(val);
(*(self.reg)).pfifo.set_rxfe(enabled).set_txfe(enabled);
}
}

impl CharIO for UART {
fn putc(&self, value: char) {
wait_for!(self.reg.S1() as u8 & S1TDREmpty == S1TDREmpty);
self.reg.set_D(value as u8);
wait_for!(self.reg.s1.tdre());
self.reg.d.set_re(value as u8);
}
}

static S1TDREmpty: u8 = 0b1000_0000;
/// Register definitions
pub mod reg {
use lib::volatile_cell::VolatileCell;
use core::ops::Drop;
use core::intrinsics::abort;

static PFIFOTxFifoEnabled: u8 = 0b1000_0000;
static PFIFORxFifoEnabled: u8 = 0b0000_1000;
ioregs!(UART = {
0x0 => reg8 bdh { //! baud rate high
0..4 => sbr, //= baud rate (high 5 bits)
6 => rxedgie, //= RxD input active edge interrupt enable
7 => lbkdie, //= LIN break detect interrupt enable
},

mod reg {
use lib::volatile_cell::VolatileCell;
0x1 => reg8 bdl { //! baud rate low
0..7 => sbr, //= baud rate (low 8 bits)
}

0x2 => reg8 c1 { //! Control register 1
0 => pt { //! parity type
0x0 => Even, //= even parity
0x1 => Odd, //= odd parity
}
1 => pe, //= parity enable
2 => ilt { //! idle line type select
0x0 => AfterStart, //= idle character bit count starts after start bit
0x1 => AfterStop, //= idle character bit count starts after stop bit
}
3 => wake { //! receiver wakeup method select
0x0 => IdleLineWakeup,
0x1 => AddressMarkWakeup,
}
4 => m { //! bit width mode select
0x0 => DataBits8, //= start + 8 data bits + stop
0x1 => DataBits9, //= start + 9 data bits + stop
}
5 => rsrc { //! receiver source select
0x0 => RxLoopback, //= select internal loop-back mode
0x1 => SingleWire, //= single-wire UART mode
}
6 => uartswai, //= should UART stop in Wait mode
7 => loops, //= loop mode enable
},

0x3 => reg8 c2 { //! Control register 2
0 => sbk, //= send break
1 => rwu, //= receiver wakeup control
2 => re, //= receiver enable
3 => te, //= transmitter enable
4 => ilie, //= idle line interrupt enable
5 => rie, //= receiver full interrupt enable
6 => tcie, //= transmission complete interrupt enable
7 => tie, //= transmitter interrupt enable
},

0x4 => reg8 s1 { //! Status register 1
0 => pf, //= parity error flag
1 => fe, //= framing error flag
2 => nf, //= noise flag
3 => or, //= receiver overrun flag
4 => idle, //= idle line flag
5 => rdrf, //= receive data register full flag
6 => tc, //= transmit complete flag
7 => tdre, //= transmit data register empty flag
},

ioreg_old!(UART: u8, BDH, BDL, C1, C2, S1, S2, C3, D, MA1, MA2, C4, C5, ED, MODEM, IR,
PFIFO, CFIFO, SFIFO, TWFIFO, TCFIFO, RWFIFO, RCFIFO)
reg_rw!(UART, u8, BDH, set_BDH, BDH)
reg_rw!(UART, u8, BDL, set_BDL, BDL)
reg_rw!(UART, u8, C1, set_C1, C1)
reg_rw!(UART, u8, C2, set_C2, C2)
reg_r!( UART, u8, S1, S1)
reg_rw!(UART, u8, S2, set_S2, S2)
reg_rw!(UART, u8, C3, set_C3, C3)
reg_rw!(UART, u8, D, set_D, D)
reg_rw!(UART, u8, MA1, set_MA1, MA1)
reg_rw!(UART, u8, MA2, set_MA2, MA2)
reg_rw!(UART, u8, C4, set_C4, C4)
reg_rw!(UART, u8, C5, set_C5, C5)
reg_rw!(UART, u8, ED, set_ED, ED)
reg_rw!(UART, u8, MODEM, set_MODEM, MODEM)
reg_rw!(UART, u8, IR, set_IR, IR)
reg_rw!(UART, u8, PFIFO, set_PFIFO, PFIFO)
reg_rw!(UART, u8, CFIFO, set_CFIFO, CFIFO)
reg_rw!(UART, u8, SFIFO, set_SFIFO, SFIFO)
reg_rw!(UART, u8, TWFIFO, set_TWFIFO, TWFIFO)
reg_r!( UART, u8, TCFIFO, TCFIFO)
reg_rw!(UART, u8, RWFIFO, set_RWFIFO, RWFIFO)
reg_r!( UART, u8, RCFIFO, RCFIFO)
// FIXME(bgamari): Specialized registers omitted
0x5 => reg8 s2 { //! Status register 2
0 => raf: ro, //= reciever active flag
1 => lbkde, //= LIN break detection enable
2 => brk13, //= break transmit character length
3 => rwuid, //= receive wakeup idle detect
4 => rxinv, //= receive data inversion
5 => msbf, //= most significant bit first
6 => rxedgif, //= RxD pin active edge interrupt flag
7 => lbkdif, //= LIN break detect interrupt flag
},

0x6 => reg8 c3 { //! Control register 3
0 => peie, //= parity error interrupt enable
1 => feie, //= framing error interrupt enable
2 => neie, //= noise error interrupt enable
3 => orie, //= overrun error interrupt enable
4 => txinv, //= transmit data inversion
5 => txdir, //= transmitter pin data direction in single-wire mode
6 => t8, //= transmit bit 8
7 => r8: ro, //= receieved bit 8
},

0x7 => reg8 d { //! Data register
0..7 => re, //= reads return the contents of the receive data register,
//= writes go to the transmit data register.
},

0x8 => reg8 ma1 { //! Match address register 1
0..7 => ma, //= match address
},

0x9 => reg8 ma2 { //! Match address register 2
0..7 => ma, //= match address
},

0xa => reg8 c4 { //! Control register 4
0..4 => brfa, //= baud rate fine adjust
5 => m10, //= 10-bit mode select
6 => maen2, //= match address 2 enable
7 => maen1, //= match address 1 enable
},

0xb => reg8 c5 { //! Control register 5
5 => rdmas, //= receiver full DMA select
7 => tdmas, //= transmitter DMA select
},

0xc => reg8 ed { //! Extended data register
6 => paritye: ro, //= The current received data word has a parity error
7 => noisy: ro, //= The current received data word was received with noise
},

0xd => reg8 modem { //! Modem register
0 => txctse, //= transmitter clear-to-send enable
1 => txrese, //= transmitter request-to-send enable
2 => txrtspol, //= transmitter request-to-send polarity
3 => rxrtse, //= receiver request-to-send polarity
},

0xe => reg8 ir { //! Infrared register
0..1 => tnp { //! transmitter narrow pulse
0 => PULSE_3_16,
1 => PULSE_1_16,
2 => PULSE_1_32,
3 => PULSE_1_4,
},
2 => iren, //= infrared enable
},

0x10 => reg8 pfifo { //! FIFO parameters
0..2 => rxfifosize: ro, //= receive FIFO buffer depth
3 => rxfe, //= receive FIFO enable
4..6 => txfifosize: ro, //= transmit FIFO buffer depth
7 => txfe, //= transmit FIFO enable
},

0x11 => reg8 cfifo { //! FIFO control
0 => rxufe, //= receive FIFO underflow interrupt enable
1 => txofe, //= transmit FIFO overflow interrupt enable
2 => rxofe, //= receive FIFO overflow interrupt enable
6 => rxflush: wo, //= flush receive FIFO
7 => txflush: wo, //= flush transmit FIFO
},

0x12 => reg8 sfifo { //! FIFO status
0 => rxuf, //= recieve FIFO underflow flag
1 => txof, //= transmit FIFO overflow flag
2 => rxof, //= recieve FIFO overflow flag
6 => rxempt: ro, //= recieve FIFO empty flag
7 => txempt: ro, //= transmit FIFO empty flag
},

0x13 => reg8 twfifo { //! Transmit FIFO watermark
0..7 => txwater, //= number of data words to transmit before generating
//= an interrupt or DMA request
},

0x14 => reg8 tcfifo { //! Transmit FIFO count
0..7 => txcount, //= number of data words in the transmit FIFO buffer.
}

0x15 => reg8 rwfifo { //! Receive FIFO watermark
0..7 => rxwater, //= number of data words to receive before generating
//= an interrupt or DMA request
},

0x16 => reg8 rcfifo { //! Receive FIFO count
0..7 => rxcount, //= number of data words in the receive FIFO buffer.
},

// FIXME(bgamari): Specialized registers omitted
})

impl UART_c1_m {
/// UART data word length flag value from bit count
pub fn from_u8(val: u8) -> UART_c1_m {
match val {
8 => DataBits8,
9 => DataBits9,
_ => unsafe { abort() },
}
}
}

extern {
#[link_name="k20_iomem_UART1"] pub static UART0: UART;
Expand Down

3 comments on commit 7c10b28

@hacknbot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge sha eec1aa1 is stale.

@hacknbot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging bgamari/zinc/ioreg-k20 = 7c10b28 into auto

@hacknbot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bgamari/zinc/ioreg-k20 = 7c10b28 merged ok, testing candidate = 7cdf82c

Please sign in to comment.