全部博文(72)
2010年(72)
分类: LINUX
2010-09-24 09:01:23
1.发送和接收
发送:循环buffer à发送fifoà发送移位寄存器
接收:接收移位寄存器à接收fifo àFlip_buf
发送的过程是:把数据写到发送fifo中,fifo把收到的数据传给发送移位寄存器(自动的,非driver控制),然后每个时钟脉冲往串口线上写一bit数据。
接收的过程是:接收移位寄存器收到数据,发送给接收fifo,接收fifo事先设置好了触发门限,当里面的数据量超过门限时就会触发一个中断,调用驱动中的中断处理函数,把数据写到flip_buf中。
2.寄存器
|
Word Length :数据位长度
Number of Stop Bit :停止位数
Parity Mode :奇偶校验位类型
Infra-Red Mode :UART/红外模式选择(当以UART模式工作时,需设为“
|
Receive Mode:选择接收模式。如果是采用DMA模式的话,还需要指定说使用的DMA信道。
Transmit Mode :同上。
Send Break Signal :选择是否在传1帧资料中途发送Break信号。
Loopback Mode :选择是否将UART置于Loopback测试模式。
Rx Error Status Interrupt Enable :选择是否使能当发生接收异常时,是否产生接收错误中断。
Rx Time Out Enable :是否使能接收超时中断。
Rx Interrupt Type :选择接收中断类型。
选择0:Pulse(脉冲式/边沿式中断。非FIFO模式时,一旦接收缓冲区中有数据,即产生一个中断;为FIFO模式时,一旦当FIFO中的资料达到一定的触发水平后,即产生一个中断)
选择1:Level(电平模式中断。非FIFO模式时,只要接收缓冲区中有数据,即产生中断;为FIFO模式时,只有FIFO中的资料达到触发水平后,即产生中断)
Tx Interrupt Type :类同于Rx Interrupt Type
|
FIFO Enable :FIFO使能选择。
Rx FIFO Reset :选择当复位接收FIFO时是否自动清除FIFO中的内容。
Tx FIFO Reset :选择当复位发送FIFO时是否自动清除FIFO中的内容。
Rx FIFO Trigger Level :选择接收FIFO的触发水平。
Tx FIFO Trigger Level :选择发送FIFO的触发水平。
UART TX/RX Status Register
|
Receive buffer data ready :当接收缓冲寄存器从UART接收端口接收到有效资料时将自动置“
Transmit buffer empty :当发送缓冲寄存器中为空,自动置“
Transmitter empty :当发送缓冲器中已经没有有效资料时,自动置“
|
Rx FIFO Count :接收FIFO中当前存放的字节数。
Tx FIFO Count :发送FIFO中当前存放的字节数。
Rx FIFO Full :为“1“表明接收FIFO已满。
Tx FIFO Full :为“1“表明发送FIFO已满。
模块初始化函数:
static int __init s
{
return uart_register_driver(&s
}
使用uart_register_driver注册串口驱动。
static struct uart_driver s
owner: THIS_MODULE,
normal_major: SERIAL_S
normal_name: "ttyS%d",
callout_name: "cua%d",
normal_driver: &normal,
callout_major: CALLOUT_S
callout_driver: &callout,
table: s
termios: s
termios_locked: s
minor: MINOR_START,
nr: UART_NR,
port: s
cons: S
};
static struct uart_port s
{
iobase: (unsigned long)(UART0_CTL_BASE),
iotype: SERIAL_IO_PORT,
irq: IRQ_RXD0,
uartclk: 130252800,
fifosize: 16,
ops: &s
type: PORT_S
flags: ASYNC_BOOT_AUTOCONF,
},
。。。。。。 。。。。。。。 。。。。。。。
};
static struct uart_ops s
tx_empty: s
set_mctrl: s
get_mctrl: s
stop_tx: s
start_tx: s
stop_rx: s
enable_ms: s
break_ctl: s
startup: s
shutdown: s
change_speed: s
type: s
config_port: s
release_port: s
request_port: s
};
3.1 阻止发送函数uart_stop_tx
static void s
{
disable_irq(TX_IRQ(port));
}
停止发送的功能,其内部的函数disable_irq是停止中断的功能 ,发送数据是通过中断来完成的,关闭中断也就关闭了发送。
3.2 发送使能函数uart_start_tx
static void s
u_int from_tty)
{
enable_irq(TX_IRQ(port));
}
与上面的过程类似,就是一个相反的过程
3.3 阻止接收函数uart_stop_rx
static void s
{
disable_irq(RX_IRQ(port));
}
3.4 发送缓冲空判断函数uart_tx_empty
static u_int s
{
return (UART_UTRSTAT(port) & UTRSTAT_TR_EMP ? 0 : TIOCSER_TEMT);
}
如果发送缓冲为空则返回0,否则返回1。
3.5 获取控制信息函数uart_get_mctrl
static u_int s
{
return (TIOCM_CTS | TIOCM_DSR | TIOCM_CAR);
}
获得控制信息, TIOCM_CTS ,TIOCM_DSR 和TIOCM_CAR,这几个宏代表串口的控制信息, 分别是clear to send,data set ready和data carrier detect(详见Serial Programming Guide for POSIX Operating Systems)
3.6 接收中断函数uart_rx_interrupt
static void s
{
struct uart_info *info = dev_id;
struct tty_struct *tty = info->tty;
unsigned int status, ch, max_count = 256;
struct uart_port *port = info->port;
status = UART_UTRSTAT(port);
while ((status & UTRSTAT_RX_RDY) && max_count--)
{
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
{
tty->flip.tqueue.routine((void *) tty);
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
printk(KERN_WARNING "TTY_DONT_FLIP set\n");
return;
}
}
ch = UART_URXH(port);
*tty->flip.char_buf_ptr = ch;
*tty->flip.flag_buf_ptr = TTY_NORMAL;
port->icount.rx++;
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
tty->flip.count++;
status = UART_UTRSTAT(port);
}
tty_flip_buffer_push(tty);
return;
}
功能:主要是是while大循环,首先看循环判断条件status & UTRSTAT_RX_RDY,前面有status = UART_UTRSTAT(port),查2410的datasheet, status & UTRSTAT_RX_RDY这个位是判断接收buffer内是否还有有效数据?按道理一次中断只是把接收的fifobuffer中的数据放到flipbuffer中去,接收的fifo的中断门限是4-12字节,进行一次接收往往要中断好多次,这样中断开销比较大,所以在while的循环条件中判断一下是否还有接收的有效数据,如果有,就继续在中断程序中继续接收,当然,永远都在接收中断中(如果一直有数据要接收)也不合适,所以while循环还有计数,最多循环256次。
在循环中,首先是要判断一下接收数据用的flip-buffer是不是已经满了, if (tty->flip.count >= TTY_FLIPBUF_SIZE)如果满了,就要跳到另一个buffer上去, tty->flip.tqueue.routine((void *) tty)是用来实现跳到另一个buffer上的功能,然后把收到的数据写到flip-buffer中,相应的状态,统计数据都要改,接着再来while 循环,循环结束后就要调用tty_flip_buffer_push(tty)来让用户把存在缓冲里的数据取走,接收一次都要把缓存清空。