diff options
| author | mbbill <[email protected]> | 2009-12-29 07:17:58 +0000 |
|---|---|---|
| committer | mbbill <[email protected]> | 2009-12-29 07:17:58 +0000 |
| commit | 79ca654e1362270c5994eba864a1ddcc78e6cbaa (patch) | |
| tree | fa67fb76afce134a9e049df94403a65398ef3f93 /bsp/sam7x/serial.c | |
| parent | 78de03446bdc2ed0c56e76c0beff8221a358c250 (diff) | |
ADD: Add abort handler, it will terminate current thread by default.
ADD: Merged svc, abort and irq mode stack.
ADD: Changed MDK project to new format.
FIX: Removed the "static" qualifier of rt_thread_exit().
FIX: Change AT91SAM7X.h to the standard header(AT91SAM7X256.h) of RealView MDK. (not all of them are changed, e.g. sd.c)
FIX: Moved some board-dependent files to bsp.
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@257 bbd45198-f89e-11dd-88c7-29a3b14d5316
Diffstat (limited to 'bsp/sam7x/serial.c')
| -rw-r--r-- | bsp/sam7x/serial.c | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/bsp/sam7x/serial.c b/bsp/sam7x/serial.c new file mode 100644 index 0000000000..afc61c8165 --- /dev/null +++ b/bsp/sam7x/serial.c @@ -0,0 +1,396 @@ +/* + * File : serial.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-23 Bernard first version + * 2009-05-14 Bernard add RT-THread device interface + */ + +#include <rthw.h> +#include <rtthread.h> + +#include "AT91SAM7X.h" +#include "serial.h" + +/** + * @addtogroup AT91SAM7X256 + */ +/*@{*/ +typedef volatile rt_uint32_t REG32; +struct rt_at91serial_hw +{ + REG32 US_CR; // Control Register + REG32 US_MR; // Mode Register + REG32 US_IER; // Interrupt Enable Register + REG32 US_IDR; // Interrupt Disable Register + REG32 US_IMR; // Interrupt Mask Register + REG32 US_CSR; // Channel Status Register + REG32 US_RHR; // Receiver Holding Register + REG32 US_THR; // Transmitter Holding Register + REG32 US_BRGR; // Baud Rate Generator Register + REG32 US_RTOR; // Receiver Time-out Register + REG32 US_TTGR; // Transmitter Time-guard Register + REG32 Reserved0[5]; // + REG32 US_FIDI; // FI_DI_Ratio Register + REG32 US_NER; // Nb Errors Register + REG32 Reserved1[1]; // + REG32 US_IF; // IRDA_FILTER Register + REG32 Reserved2[44]; // + REG32 US_RPR; // Receive Pointer Register + REG32 US_RCR; // Receive Counter Register + REG32 US_TPR; // Transmit Pointer Register + REG32 US_TCR; // Transmit Counter Register + REG32 US_RNPR; // Receive Next Pointer Register + REG32 US_RNCR; // Receive Next Counter Register + REG32 US_TNPR; // Transmit Next Pointer Register + REG32 US_TNCR; // Transmit Next Counter Register + REG32 US_PTCR; // PDC Transfer Control Register + REG32 US_PTSR; // PDC Transfer Status Register +}; + +struct rt_at91serial +{ + struct rt_device parent; + + struct rt_at91serial_hw* hw_base; + rt_uint16_t peripheral_id; + rt_uint32_t baudrate; + + /* reception field */ + rt_uint16_t save_index, read_index; + rt_uint8_t rx_buffer[RT_UART_RX_BUFFER_SIZE]; +}; +#ifdef RT_USING_UART1 +struct rt_at91serial serial1; +#endif +#ifdef RT_USING_UART2 +struct rt_at91serial serial2; +#endif + +static void rt_hw_serial_isr(int irqno) +{ + rt_base_t level; + struct rt_device* device; + struct rt_at91serial* serial = RT_NULL;
+ +#ifdef RT_USING_UART1 + if (irqno == AT91C_ID_US0) + { + /* serial 1 */ + serial = &serial1; + }
+#endif
+
+#ifdef RT_USING_UART2 + if (irqno == AT91C_ID_US1) + { + /* serial 2 */ + serial = &serial2; + }
+#endif + RT_ASSERT(serial != RT_NULL); + + /* get generic device object */ + device = (rt_device_t)serial; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* get received character */ + serial->rx_buffer[serial->save_index] = serial->hw_base->US_RHR; + + /* move to next position */ + serial->save_index ++; + if (serial->save_index >= RT_UART_RX_BUFFER_SIZE) + serial->save_index = 0; + + /* if the next position is read index, discard this 'read char' */ + if (serial->save_index == serial->read_index) + { + serial->read_index ++; + if (serial->read_index >= RT_UART_RX_BUFFER_SIZE) + serial->read_index = 0; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* indicate to upper layer application */ + if (device->rx_indicate != RT_NULL) + device->rx_indicate(device, 1); + + /* ack interrupt */ + AT91C_AIC_EOICR = 1; +} + +static rt_err_t rt_serial_init (rt_device_t dev) +{ + rt_uint32_t bd; + struct rt_at91serial* serial = (struct rt_at91serial*) dev; + + RT_ASSERT(serial != RT_NULL); + /* must be US0 or US1 */ + RT_ASSERT((serial->peripheral_id != AT91C_ID_US0) && + (serial->peripheral_id != AT91C_ID_US1)); + + /* Enable Clock for USART */ + AT91C_PMC_PCER = 1 << serial->peripheral_id; + + /* Enable RxD0 and TxDO Pin */ + if (serial->peripheral_id == AT91C_ID_US0) + { + /* set pinmux */ + AT91C_PIO_PDR = (1 << 5) | (1 << 6); + } + else if (serial->peripheral_id == AT91C_ID_US1) + { + /* set pinmux */ + AT91C_PIO_PDR = (1 << 21) | (1 << 22); + } + + serial->hw_base->US_CR = AT91C_US_RSTRX | /* Reset Receiver */ + AT91C_US_RSTTX | /* Reset Transmitter */ + AT91C_US_RXDIS | /* Receiver Disable */ + AT91C_US_TXDIS; /* Transmitter Disable */ + + serial->hw_base->US_MR = AT91C_US_USMODE_NORMAL | /* Normal Mode */ + AT91C_US_CLKS_CLOCK | /* Clock = MCK */ + AT91C_US_CHRL_8_BITS | /* 8-bit Data */ + AT91C_US_PAR_NONE | /* No Parity */ + AT91C_US_NBSTOP_1_BIT; /* 1 Stop Bit */ + + /* set baud rate divisor */ + bd = ((MCK*10)/(serial->baudrate * 16)); + if ((bd % 10) >= 5) bd = (bd / 10) + 1; + else bd /= 10; + + serial->hw_base->US_BRGR = bd; + serial->hw_base->US_CR = AT91C_US_RXEN | /* Receiver Enable */ + AT91C_US_TXEN; /* Transmitter Enable */ + + /* reset rx index */ + serial->save_index = 0; + serial->read_index = 0; + + /* reset rx buffer */ + rt_memset(serial->rx_buffer, 0, RT_UART_RX_BUFFER_SIZE); + + return RT_EOK; +} + +static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag) +{ + struct rt_at91serial *serial = (struct rt_at91serial*)dev; + RT_ASSERT(serial != RT_NULL); + + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + /* enable UART rx interrupt */ + serial->hw_base->US_IER = 1 << 0; /* RxReady interrupt */ + serial->hw_base->US_IMR |= 1 << 0; /* umask RxReady interrupt */ + + /* install UART handler */ + rt_hw_interrupt_install(serial->peripheral_id, rt_hw_serial_isr, RT_NULL); + AT91C_AIC_SMR(serial->peripheral_id) = 5 | (0x01 << 5); + rt_hw_interrupt_umask(serial->peripheral_id); + } + + return RT_EOK; +} + +static rt_err_t rt_serial_close(rt_device_t dev) +{ + struct rt_at91serial *serial = (struct rt_at91serial*)dev; + RT_ASSERT(serial != RT_NULL); + + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + /* disable interrupt */ + serial->hw_base->US_IDR = 1 << 0; /* RxReady interrupt */ + serial->hw_base->US_IMR &= ~(1 << 0); /* mask RxReady interrupt */ + } + + serial->hw_base->US_CR = AT91C_US_RSTRX | /* Reset Receiver */ + AT91C_US_RSTTX | /* Reset Transmitter */ + AT91C_US_RXDIS | /* Receiver Disable */ + AT91C_US_TXDIS; /* Transmitter Disable */ + + return RT_EOK; +} + +static rt_size_t rt_serial_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + rt_uint8_t* ptr; + struct rt_at91serial *serial = (struct rt_at91serial*)dev; + RT_ASSERT(serial != RT_NULL); + + /* point to buffer */ + ptr = (rt_uint8_t*) buffer; + + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + while (size) + { + /* interrupt receive */ + rt_base_t level; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + if (serial->read_index != serial->save_index) + { + *ptr = serial->rx_buffer[serial->read_index]; + + serial->read_index ++; + if (serial->read_index >= RT_UART_RX_BUFFER_SIZE) + serial->read_index = 0; + } + else + { + /* no data in rx buffer */ + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + break; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + ptr ++; + size --; + } + + return (rt_uint32_t)ptr - (rt_uint32_t)buffer; + } + else if (dev->flag & RT_DEVICE_FLAG_DMA_RX) + { + /* not support right now */ + RT_ASSERT(0); + } + else + { + /* poll mode */ + while (size) + { + /* Wait for Full Rx Buffer */ + while (!(serial->hw_base->US_CSR & AT91C_US_RXRDY)); + + /* Read Character */ + *ptr = serial->hw_base->US_RHR; + ptr ++; + size --; + } + + return (rt_size_t)ptr - (rt_size_t)buffer; + } + + return 0; +} + +static rt_size_t rt_serial_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_uint8_t* ptr; + struct rt_at91serial *serial = (struct rt_at91serial*)dev; + RT_ASSERT(serial != RT_NULL); + + ptr = (rt_uint8_t*) buffer; + if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY) + { + if (dev->flag & RT_DEVICE_FLAG_STREAM) + { + /* it's a stream mode device */ + while (size) + { + /* stream mode */ + if (*ptr == '\n') + { + while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY)); + serial->hw_base->US_THR = '\r'; + } + + /* Wait for Empty Tx Buffer */ + while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY)); + + /* Transmit Character */ + serial->hw_base->US_THR = *ptr; + ptr ++; + size --; + } + } + else + { + while (size) + { + /* Wait for Empty Tx Buffer */ + while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY)); + + /* Transmit Character */ + serial->hw_base->US_THR = *ptr; + ptr ++; + size --; + } + } + } + + return (rt_size_t)ptr - (rt_size_t)buffer; +} + +static rt_err_t rt_serial_control (rt_device_t dev, rt_uint8_t cmd, void *args) +{ + return RT_EOK; +} + +rt_err_t rt_hw_serial_init() +{ + rt_device_t device; + +#ifdef RT_USING_UART1 + device = (rt_device_t) &serial1; + + /* init serial device private data */ + serial1.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US0; + serial1.peripheral_id = AT91C_ID_US0; + serial1.baudrate = 115200; + + /* set device virtual interface */ + device->init = rt_serial_init; + device->open = rt_serial_open; + device->close = rt_serial_close; + device->read = rt_serial_read; + device->write = rt_serial_write; + device->control = rt_serial_control; + + /* register uart1 on device subsystem */ + rt_device_register(device, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX); +#endif + +#ifdef RT_USING_UART2 + device = (rt_device_t) &serial2; + + serial2.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US1; + serial2.peripheral_id = AT91C_ID_US1; + serial2.baudrate = 115200; + + /* set device virtual interface */ + device->init = rt_serial_init; + device->open = rt_serial_open; + device->close = rt_serial_close; + device->read = rt_serial_read; + device->write = rt_serial_write; + device->control = rt_serial_control; + + /* register uart2 on device subsystem */ + rt_device_register(device, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX); +#endif + + return RT_EOK; +} + +/*@}*/ |
