/* * 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 * * 2011-12-17 nl1031 MicroBlaze */ #include <rthw.h> #include <rtthread.h> #include "serial.h" typedef volatile rt_uint32_t REG32; struct rt_mb_uart_lite_hw { REG32 Rx_FIFO; // Receiver Holding Register REG32 Tx_FIFO; // Transmitter Holding Register REG32 STAT_REG; // Channel Status Register REG32 CTRL_REG; // Control Register }; struct rt_mb_uart_lite { struct rt_device parent; struct rt_mb_uart_lite_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_mb_uart_lite serial1; #endif static void rt_hw_serial_isr(void) { unsigned int status; rt_base_t level; struct rt_device* device; struct rt_mb_uart_lite* serial = RT_NULL; #ifdef RT_USING_UART1 /* serial 1 */ serial = &serial1; #endif RT_ASSERT(serial != RT_NULL); /* get generic device object */ device = (rt_device_t)serial; /* disable interrupt */ level = rt_hw_interrupt_disable(); /* get uart status register */ status = serial->hw_base->STAT_REG; while (status & XUL_SR_RX_FIFO_VALID_DATA) { /* get received character */ serial->rx_buffer[serial->save_index] = serial->hw_base->Rx_FIFO; /* 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; } status = serial->hw_base->STAT_REG; } /* enable interrupt */ rt_hw_interrupt_enable(level); /* indicate to upper layer application */ if (device->rx_indicate != RT_NULL) device->rx_indicate(device, 1); } static rt_err_t rt_serial_init (rt_device_t dev) { struct rt_mb_uart_lite* serial = (struct rt_mb_uart_lite*) dev; RT_ASSERT(serial != RT_NULL); RT_ASSERT(serial->peripheral_id != XPAR_UARTLITE_1_DEVICE_ID); /* 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_mb_uart_lite *serial = (struct rt_mb_uart_lite*)dev; RT_ASSERT(serial != RT_NULL); if (dev->flag & RT_DEVICE_FLAG_INT_RX) { /* enable UART rx interrupt */ serial->hw_base->CTRL_REG = XUL_CR_ENABLE_INTR; /* enable interrupt */ /* install UART handler */ rt_hw_interrupt_install(serial->peripheral_id, (rt_isr_handler_t)rt_hw_serial_isr, RT_NULL); rt_hw_interrupt_umask(serial->peripheral_id); } return RT_EOK; } static rt_err_t rt_serial_close(rt_device_t dev) { struct rt_mb_uart_lite *serial = (struct rt_mb_uart_lite*)dev; RT_ASSERT(serial != RT_NULL); if (dev->flag & RT_DEVICE_FLAG_INT_RX) { /* disable interrupt */ serial->hw_base->CTRL_REG = 0; /* RxReady interrupt */ } 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_mb_uart_lite *serial = (struct rt_mb_uart_lite*)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->STAT_REG & XUL_SR_RX_FIFO_VALID_DATA)); /* Read Character */ *ptr = serial->hw_base->Rx_FIFO; 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_mb_uart_lite *serial = (struct rt_mb_uart_lite*)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->STAT_REG & XUL_SR_TX_FIFO_EMPTY)); serial->hw_base->Tx_FIFO = '\r'; } /* Wait for Empty Tx Buffer */ while (!(serial->hw_base->STAT_REG & XUL_SR_TX_FIFO_EMPTY)); /* Transmit Character */ serial->hw_base->Tx_FIFO = *ptr; if (*ptr & 1) rt_hw_board_led_on(2); else rt_hw_board_led_off(2); ptr ++; size --; } } else { while (size) { /* Wait for Empty Tx Buffer */ while (!(serial->hw_base->STAT_REG & XUL_SR_TX_FIFO_EMPTY)); /* Transmit Character */ serial->hw_base->Tx_FIFO = *ptr; if (*ptr & 1) rt_hw_board_led_on(2); else rt_hw_board_led_off(2); 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; #ifndef RT_USING_CONSOLE int Status; /* * Initialize the UartLite driver so that it is ready to use. */ Status = XUartLite_Initialize(&uart_lite, RS232_DEVICE_ID); if (Status != XST_SUCCESS) { return; } #endif #ifdef RT_USING_UART1 device = (rt_device_t) &serial1; /* init serial device private data */ serial1.hw_base = (struct rt_mb_uart_lite_hw*)XPAR_USB_UART_BASEADDR; serial1.peripheral_id = XPAR_UARTLITE_1_DEVICE_ID; 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 return RT_EOK; }