📄 serial-lpc.c
字号:
/***************************************************************************\
Copyright (c) 2004-2007 threewater@up-tech.com, All rights reserved.
by threewter 2004.4.26
\***************************************************************************/
/***************************************************************************\
#说明: lpc2xxx串口驱动程序for uCOS-II
---------------------------------- Bug --------------------------------------
---------------------------------- TODO list --------------------------------------
----------------------------------修正--------------------------------------
2005-5-30 创建
\***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "../inc/sys/uart.h"
#include "../inc/drivers.h"
#include "../inc/drv/serial.h"
#include "../inc/sys/io.h"
#include <uhal/isr.h>
#define GENERATOR_CLK Fpclk
#define FIFO_LENGTH 16
//Register OFFSET in 16550
#define Uart_RBR (0x0)
#define Uart_THR (0x0)
#define Uart_DLL (0x0)
#define Uart_IER (0x4)
#define Uart_DLM (0x4)
#define Uart_IIR (0x8)
#define Uart_FCR (0x8)
#define Uart_LCR (0xc)
#define Uart_MCR (0x10)
#define Uart_LSR (0x14)
#define Uart_MSR (0x18)
#define Uart_SCR (0x1c)
#define Uart_UartEN (0x30)
#define Uart_LSR_TEMT (1<<6)
#define Uart_LSR_THRE (1<<5)
#define Uart_LSR_DR (1)
#define Uart_FCR_FIFOEN (1)
#define Uart_FCR_RCVR (1<<1)
#define Uart_FCR_XMIT (1<<2)
#define Serial_Isr(n) (UART0_OFFSET+n) //串口中断号
const static int Uart_Base[]={U0BASE, U1BASE};
static U8 serial_sending[NumberOfArray(Uart_Base)];
#define serial_inb(ndev, offset) _inb(Uart_Base[ndev] + offset)
#define serial_outb(ndev, offset, ch) _outb(Uart_Base[ndev] + offset, ch)
static void serial_isr(int vector, int ndev);
__inline static int serial_init(int ndev, int baudrate)
{
int div=(GENERATOR_CLK*10/16/baudrate+5)/10;
serial_outb(ndev, Uart_UartEN, 1); //enable uart
//set serial baudrate
serial_outb(ndev, Uart_LCR, 0x80); //DLAB=1
serial_outb(ndev, Uart_DLL, div);
serial_outb(ndev, Uart_DLM, div>>8);
serial_outb(ndev, Uart_LCR, 0x03); //DLAB=0, 8bit,1 stop, N mode
serial_outb(ndev, Uart_FCR, Uart_FCR_FIFOEN); //FIFO on
serial_outb(ndev, Uart_IER,0x0); //disable all interrupt
serial_outb(ndev, Uart_MCR,0x03); //set RTS and DTR
serial_sending[ndev]=0;
return 0;
}
__inline static int serial_open(int ndev)
{
serial_outb(ndev, Uart_IER,0x1); //enable recieve interrupt
SetISR_Interrupt(Serial_Isr(ndev), (Interrupt_func_t)serial_isr, (void*)ndev);
return 0;
}
__inline static int serial_read(int ndev)
{
return serial_inb(ndev, Uart_RBR);
}
__inline static int serial_write(int ndev)
{
int data;
if(serial_sending[ndev])
return 0;
while(serial_inb(ndev, Uart_LSR) & Uart_LSR_THRE){
data=Get_SndBuffer(ndev);
if(data<0)
return 0;
if(data == 13)
serial_outb(ndev, Uart_THR, 10);
serial_outb(ndev, Uart_THR, data);
}
serial_sending[ndev]=1;
serial_outb(ndev, Uart_IER,0x3); //enable recieve and send interrupt
return 0;
}
__inline static int serial_writepoll(int ndev, int ch)
{
serial_outb(ndev, Uart_THR, ch);
while(!(serial_inb(ndev, Uart_LSR) & Uart_LSR_THRE));
return 0;
}
__inline static int serial_poll(int ndev)
{
return (serial_inb(ndev, Uart_LSR) & Uart_LSR_DR);
}
//采用中断的方式获取串口数据
static void serial_isr(int vector, int ndev)
{
int lsr;
while((serial_inb(ndev, Uart_IIR) & 0x01) == 0)/* 有中断未处理完 */
{
lsr = serial_inb(ndev, Uart_LSR);
//(lsr & Uart_LSR_THRE) ==1 判断是否有可读数据
//isr 包含了多个信息,这里只 处理了接收和发送的中断
if((lsr & Uart_LSR_THRE) && serial_sending[ndev]==1){ // THRE中断//
int data, i;
for(i=0; i<FIFO_LENGTH; i++){
data=Get_SndBuffer(ndev);
if(data<0){ //发送缓冲区空
serial_outb(ndev, Uart_IER, 0x1); //关闭发送中断
serial_sending[ndev]=0;
break;
}
serial_outb(ndev, Uart_THR, data);
}
}
if(lsr & Uart_LSR_DR){ //接收中断
do{
Put_RevBuffer(ndev, serial_read(ndev));
}while(serial_inb(ndev, Uart_LSR) & Uart_LSR_DR);
}
}
}
__inline static int serial_flush_input(int ndev)
{
serial_outb(ndev, Uart_FCR, Uart_FCR_RCVR);
return 0;
}
/**
//真正的刷新缓存函数,将 寄存器的数据全部读出
//这里我默认的触发机制时,有足够的数据就才触发中断,
//即使没有中断产生,但是有接收的数据Uart_LSR_DR 对应的值也是1
__inline static int serial_flush_input(int ndev)
{
do{
Put_RevBuffer(ndev, serial_read(ndev));
}while(serial_inb(ndev, Uart_LSR) & Uart_LSR_DR);
}
*/
__inline static int serial_flush_output(int ndev)
{
serial_outb(ndev, Uart_FCR, Uart_FCR_XMIT);
return 0;
}
#define DefSerialN(n) static int lpc2xxx_serial##n##_init(int baud){return serial_init(n,baud);}\
static int lpc2xxx_serial##n##_open(void){return serial_open(n);}\
static int lpc2xxx_serial##n##_read(void){return serial_read(n);}\
static int lpc2xxx_serial##n##_write(void){return serial_write(n);}\
static int lpc2xxx_serial##n##_writepoll(int ch){return serial_writepoll(n, ch);}\
static int lpc2xxx_serial##n##_poll(void){return serial_poll(n);}\
static int lpc2xxx_serial##n##_flush_input(void){return serial_flush_input(n);}\
static int lpc2xxx_serial##n##_flush_output(void){return serial_flush_output(n);}
/* export serial driver */
#define ExportSerialN(n) const serial_driver_t lpc2xxx_serial##n##_driver = { \
lpc2xxx_serial##n##_init, \
lpc2xxx_serial##n##_open,\
lpc2xxx_serial##n##_read,\
lpc2xxx_serial##n##_write,\
lpc2xxx_serial##n##_writepoll,\
lpc2xxx_serial##n##_poll,\
lpc2xxx_serial##n##_flush_input,\
lpc2xxx_serial##n##_flush_output,\
}
DefSerialN(0)
DefSerialN(1)
ExportSerialN(0);
ExportSerialN(1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -