Library to access LPC17xx peripherals. It uses static inline functions, constant propagation and dead code elimination to be as fast as possible.
Dependents: Chua-VGA Wolfram-1D-VGA WolframRnd-1D-VGA Basin-VGA ... more
Diff: uart.h
- Revision:
- 0:7a91348b4a02
- Child:
- 2:148b9af2b336
diff -r 000000000000 -r 7a91348b4a02 uart.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uart.h Sun Jul 03 17:11:55 2011 +0000 @@ -0,0 +1,348 @@ +/* Copyright (C) 2010, 2011 by Ivo van Poorten <ivop@euronet.nl> + * This file is licensed under the terms of the GNU Lesser + * General Public License, version 3. + */ + +#ifndef FASTLIB_UART_H +#define FASTLIB_UART_H + +#include "fastlib/common.h" + +#define FL_UART_RBR 0x00 +#define FL_UART_THR 0x00 +#define FL_UART_DLL 0x00 + +#define FL_UART_DLM 0x04 +#define FL_UART_IER 0x04 + +#define FL_UART_IIR 0x08 +#define FL_UART_FCR 0x08 + +#define FL_UART_LCR 0x0C +#define FL_UART_MCR 0x10 /* UART1 only */ +#define FL_UART_LSR 0x14 +#define FL_UART_MSR 0x18 /* UART1 only */ +#define FL_UART_SCR 0x1C +#define FL_UART_ACR 0x20 +#define FL_UART_ICR 0x24 /* UART023 only */ +#define FL_UART_FDR 0x28 +#define FL_UART_TER 0x30 + +#define FL_UART_RS485CTRL 0x4C /* UART1 only */ +#define FL_UART_RS485ADRMATCH 0x50 /* UART1 only */ +#define FL_UART_RS485DLY 0x54 /* UART1 only */ + +#define FL_UART0_BASE 0x4000C000 +#define FL_UART1_BASE 0x40010000 +#define FL_UART2_BASE 0x40098000 +#define FL_UART3_BASE 0x4009C000 + +#define FL_UART(num, field) \ + ((volatile uint32_t *)(fl_uart_num_to_base(num) + FL_UART_##field)) + +static inline unsigned fl_uart_num_to_base(const unsigned num) { + switch(num) { + case 0: return FL_UART0_BASE; + case 1: return FL_UART1_BASE; + case 2: return FL_UART2_BASE; + default: return FL_UART3_BASE; + } +} + +static inline unsigned fl_uart_receive_byte(const unsigned uart) { + return *FL_UART(uart, RBR); +} + +static inline void fl_uart_send_byte(const unsigned uart, const unsigned byte) { + *FL_UART(uart, THR); +} + +static inline unsigned fl_uart_get_divisor_latch(const unsigned uart) { + unsigned divisor; + *FL_UART(uart, LCR) |= 1U<<7; // enable access to latch + + divisor = *FL_UART(uart, DLL) | (*FL_UART(uart, DLM) << 8); + + *FL_UART(uart, LCR) &= ~(1U<<7); // disable access to latch + return divisor; +} + +/* divisor: 16-bit value */ +static inline void fl_uart_set_divisor_latch(const unsigned uart, const unsigned divisor) { + *FL_UART(uart, LCR) |= 1U<<7; // enable access to latch + + *FL_UART(uart, DLL) = divisor & 0xff; + *FL_UART(uart, DLM) = (divisor >> 8) & 0xff; + + *FL_UART(uart, LCR) &= ~(1U<<7); // disable access to latch +} + +static inline void fl_uart_rx_data_available_interrupt_enable(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, IER) |= (1U<<0); + else *FL_UART(uart, IER) &= ~(1U<<0); +} + +static inline void fl_uart_tx_fifo_empty_interrupt_enable(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, IER) |= (1U<<1); + else *FL_UART(uart, IER) &= ~(1U<<1); +} + +static inline void fl_uart_rx_line_status_interrupt_enable(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, IER) |= (1U<<2); + else *FL_UART(uart, IER) &= ~(1U<<2); +} + +static inline void fl_uart_end_of_autobaud_interrupt_enable(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, IER) |= (1U<<8); + else *FL_UART(uart, IER) &= ~(1U<<8); +} + +static inline void fl_uart_timeout_autobaud_interrupt_enable(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, IER) |= (1U<<9); + else *FL_UART(uart, IER) &= ~(1U<<9); +} + +static inline unsigned fl_uart_interrupt_status(const unsigned uart) { + return !(*FL_UART(uart, IIR) & 1); // negate, because status is active low +} + +#define FL_UART_INTERRUPT_RLS 3 /* rx line status */ +#define FL_UART_INTERRUPT_RDA 2 /* rx data available */ +#define FL_UART_INTERRUPT_CTI 6 /* character time-out */ +#define FL_UART_INTERRUPT_THRE 1 /* tx fifo empty */ +#define FL_UART_INTERRUPT_MODEM 0 /* modem interrupt, uart1 only */ + +static inline unsigned fl_uart_get_interrupt_identification(const unsigned uart) { + return (*FL_UART(uart, IIR) >> 1) & 7; +} + +/* returns 0 or !0 */ +static inline unsigned fl_uart_end_of_autobaud_interrupt(const unsigned uart) { + return *FL_UART(uart, IIR) & (1U<<8); +} +static inline unsigned fl_uart_timeout_autobaud_interrupt(const unsigned uart) { + return *FL_UART(uart, IIR) & (1U<<9); +} + +/* call is more or less mandatory for application (page 305) */ +static inline void fl_uart_enable_fifos(const unsigned uart) { + *FL_UART(uart, FCR) |= 1U<<0; +} +/* disable/enable cycle clears fifo */ +static inline void fl_uart_disable_fifos(const unsigned uart) { + *FL_UART(uart, FCR) &= ~(1U<<0); +} + +static inline void fl_uart_reset_rx_fifo(const unsigned uart) { + *FL_UART(uart, FCR) |= 1U<<1; // bit is self-clearing +} + +static inline void fl_uart_reset_tx_fifo(const unsigned uart) { + *FL_UART(uart, FCR) |= 1U<<2; // bit is self-clearing +} + +static inline void fl_uart_enable_dma_mode(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, FCR) |= 1U<<3 ; + else *FL_UART(uart, FCR) &= ~(1U<<3); +} + +static inline void fl_uart_set_rx_trigger_level(const unsigned uart, const unsigned level) { + if (level != 14) *FL_UART(uart, FCR) &= ~(3U<<6); + switch(level) { + default: return; + case 4: *FL_UART(uart, FCR) |= 1U<<6; return; + case 8: *FL_UART(uart, FCR) |= 2U<<6; return; + case 14: *FL_UART(uart, FCR) |= 3U<<6; return; + } +} + +#define FL_UART_5BIT 0 +#define FL_UART_6BIT 1 +#define FL_UART_7BIT 2 +#define FL_UART_8BIT 3 + +#define FL_UART_1STOPBIT 0 +#define FL_UART_2STOPBITS 1 + +#define FL_UART_NO_PARITY 0 +#define FL_UART_PARITY 1 + +#define FL_UART_ODD 0 +#define FL_UART_EVEN 1 +#define FL_UART_FORCE1 2 +#define FL_UART_FORCE0 3 + +static inline void fl_uart_line_config(const unsigned uart, const unsigned wordlength, const unsigned stopbit, \ + const unsigned parity_enable, const unsigned parity_type) { + const unsigned combined = wordlength | (stopbit << 2) | (parity_enable << 3) | (parity_type << 4); + *FL_UART(uart, LCR) &= ~(0x3fU); + *FL_UART(uart, LCR) |= combined; +} + +static inline void fl_uart_break_transmission(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, LCR) |= 1U<<6 ; + else *FL_UART(uart, LCR) &= ~(1U<<6); +} + +static inline unsigned fl_uart_get_line_status(const unsigned uart) { + return *FL_UART(uart, LSR); +} + +/* read status first and use functions below to test what is happening */ +/* the reason for this is that a status read clears several bits */ + +#define FL_LSR_TEST(what, where) \ + static inline unsigned fl_uart_##what(const unsigned status) { \ + return status & (where); \ + } + +FL_LSR_TEST(rx_fifo_not_empty, 1U<<0); +FL_LSR_TEST(rx_fifo_overun_error, 1U<<1); +FL_LSR_TEST(rx_parity_error, 1U<<2); +FL_LSR_TEST(rx_framing_error, 1U<<3); +FL_LSR_TEST(rx_break_interrupt, 1U<<4); /* associated with top of fifo */ +FL_LSR_TEST(tx_send_register_empty, 1U<<5); +FL_LSR_TEST(tx_empty, 1U<<6); /* both send and status register */ +FL_LSR_TEST(rx_error_entered_fifo, 1U<<7); + +static inline void fl_uart_write_scratch_pad(const unsigned uart, const unsigned byte) { + *FL_UART(uart, SCR) = byte & 0xff; +} + +static inline unsigned fl_uart_read_scratch_pad(const unsigned uart) { + return *FL_UART(uart, SCR); +} + +static inline void fl_uart_autobaud_config(const unsigned uart, const unsigned mode, const unsigned autorestart) { + *FL_UART(uart, ACR) = (mode << 1) | (autorestart << 2); // writing zeroes to other bits has no impact (p.308/309) +} + +static inline void fl_uart_start_autobaud(const unsigned uart) { + *FL_UART(uart, ACR) |= 1; // bit is auto-clearing +} + +static inline void fl_uart_clear_end_of_autobaud_interrupt(const unsigned uart) { + *FL_UART(uart, ACR) |= 1U<<8; +} + +static inline void fl_uart_clear_autobaud_timeout_interrupt(const unsigned uart) { + *FL_UART(uart, ACR) |= 1U<<9; +} + +static inline void fl_uart_set_fractional_divider(const unsigned uart, const unsigned divaddval, const unsigned mulval) { + *FL_UART(uart, FDR) &= ~(0xff); + *FL_UART(uart, FDR) |= divaddval | (mulval<<4); +} + +static inline unsigned fl_uart_get_fractional_divider(const unsigned uart) { + return *FL_UART(uart, FDR); +} + +static inline void fl_uart_transmitter_enable(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, TER) |= 1U<<7 ; + else *FL_UART(uart, TER) &= ~(1U<<7); +} + +// infrared mode only works on uart0, 2 and 3 + +static inline void fl_uart_infrared_mode(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, ICR) |= 1U<<0; + else *FL_UART(uart, ICR) &= ~(1U<<0); +} +static inline void fl_uart_infrared_input_inverted(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, ICR) |= 1U<<1; + else *FL_UART(uart, ICR) &= ~(1U<<1); +} +static inline void fl_uart_infrared_fixed_pulsewidth(const unsigned uart, const unsigned state) { + if (state) *FL_UART(uart, ICR) |= 1U<<2; + else *FL_UART(uart, ICR) &= ~(1U<<2); +} +// see UM10360 page 312 for pulsediv values (0-7) +static inline void fl_uart_infrared_config_pulse(const unsigned uart, const unsigned pulsediv) { + *FL_UART(uart, ICR) &= ~(7U<<3); + *FL_UART(uart, ICR) |= pulsediv << 3; +} + + +// functions below only work for uart1 (full modem interface) + +static inline void fl_modem_status_interrupt_enable(const unsigned state) { + if (state) *FL_UART(1, IER) |= (1U<<3); + else *FL_UART(1, IER) &= ~(1U<<3); +} + +static inline void fl_modem_cts_interrupt_enable(const unsigned state) { + if (state) *FL_UART(1, IER) |= (1U<<7); + else *FL_UART(1, IER) &= ~(1U<<7); +} + +static inline void fl_modem_control(const unsigned dtr_control, const unsigned rts_control, const unsigned loopback, + const unsigned rts, const unsigned cts) { + *FL_UART(1, MCR) = dtr_control | (rts_control << 1) | (loopback << 4) | (rts << 6) | (cts << 7); +} + +static inline unsigned fl_modem_get_status(void) { + return *FL_UART(1, MSR); +} + +/* read status first and use functions below to test what is happening */ +/* the reason for this is that a status read clears several bits */ + +#define FL_MSR_TEST(what, where) \ + static inline unsigned fl_modem_##what(const unsigned status) { \ + return status & (where); \ + } + +FL_MSR_TEST(cts_state_changed, 1U<<0); +FL_MSR_TEST(dsr_state_changed, 1U<<1); +FL_MSR_TEST(low_to_high_ri, 1U<<2); +FL_MSR_TEST(dcd_state_changed, 1U<<3); +FL_MSR_TEST(cts_state, 1U<<4); /* clear to send */ +FL_MSR_TEST(dsr_state, 1U<<5); /* data set ready */ +FL_MSR_TEST(ri_state, 1U<<6); /* ring indicator */ +FL_MSR_TEST(dcd_state, 1U<<7); /* data carrier detect */ + +// RS-485/EIA-485 mode functions, also uart1 only + +static inline void fl_rs485_normal_multidrop_mode_enable(const unsigned state) { + if (state) *FL_UART(1, RS485CTRL) |= 1U<<0 ; + else *FL_UART(1, RS485CTRL) &= ~(1U<<0); +} + +static inline void fl_rs485_receiver_enable(const unsigned state) { + if (state) *FL_UART(1, RS485CTRL) |= 1U<<1 ; + else *FL_UART(1, RS485CTRL) &= ~(1U<<1); +} + +static inline void fl_rs485_auto_address_detect_enable(const unsigned state) { + if (state) *FL_UART(1, RS485CTRL) |= 1U<<2 ; + else *FL_UART(1, RS485CTRL) &= ~(1U<<2); +} + +static inline void fl_rs485_auto_direction_control_enable(const unsigned state) { + if (state) *FL_UART(1, RS485CTRL) |= 1U<<4 ; + else *FL_UART(1, RS485CTRL) &= ~(1U<<4); +} + +static inline void fl_rs485_direction_control_on_rts_pin(void) { + *FL_UART(1, RS485CTRL) &= ~(1U<<3); +} + +static inline void fl_rs485_direction_control_on_dtr_pin(void) { + *FL_UART(1, RS485CTRL) |= 1U<<3; +} + +static inline void fl_rs485_direction_control_polarity(const unsigned oinv) { + if (oinv) *FL_UART(1, RS485CTRL) |= 1U<<5 ; + else *FL_UART(1, RS485CTRL) &= ~(1U<<5); +} + +static inline void fl_rs485_set_address_match(const unsigned byte) { + *FL_UART(1, RS485ADRMATCH) = byte & 0xff; +} + +static inline void fl_rs485_set_delay_time(const unsigned byte) { + *FL_UART(1, RS485DLY) = byte & 0xff; +} + +#endif \ No newline at end of file