一、S3C2410内置的UART操控器
S3C2410内部具有3个独立的UART操控器,每个操控器都能够作业在Interrupt(中止)形式或DMA(直接内存拜访)形式,也便是说UART操控器能够在CPU与UART操控器传送数据的时分发生中止或DMA恳求。而且每个UART操控器均具有16字节的FIFO(先入先出寄存器),支撑的最高波特率可到达115.2Kbps
图5-11是S3C2410内部UART操控器的结构图
图5-11
经过上图咱们能够看到,每个UART操控器中大略分为发送器和接纳器两部分,在发送器中假如当时UART处于FIFO形式,则有16B的发送缓冲寄存器,一般在发送数据时CPU会将数据先暂存到这16B中来,假如当时UART处于非FIFO形式,则这16B的缓冲寄存器是没用的,咱们只用到了这16B中最低一个字节的缓冲寄存器来寄存数据也叫做Transmit Holding Register,而要害的一点是在发送器中发送缓冲器中的数据并不是直接送到输出引脚上的,还有必要要先送到发送移位寄存器也便是Transmit Shifter,然后再由Transmit Shifter送出到输出引脚。而接纳端这边大约都是相同,发送移位寄存器和接纳移位寄存器对数据的发送和接纳都是在波特率发生器发生的波特率下来进行操控的。而波特率的发生也需求在时钟源的操控下才行
UART的操作
UART的操作分为以下几个部分分别是数据发送、数据接纳、发生中止、发生波特率、Loopback形式、红外形式以及主动流控形式。
数据发送:
发送的数据帧格局是能够编程设置的。它包含了开始位、5~8个数据位、可选的奇偶校验位以及1~2位中止位。这些都是经过UART的操控寄存器 ULCONn 来设置的。
数据接纳:
同发送相同,接纳的数据帧格局也是能够进行编程设置的。此外,还具有了检测溢出犯错、奇偶校验犯错、帧犯错等犯错检测,而且每种过错都能够设置相应的过错标志。
主动流控形式:
S3C2410的UART0和UART1都能够经过各自的nRTS和nCTS信号来完成主动流控。在主动流控(AFC)形式下nRTS取决于接纳端的状况,而nCTS操控了发送端的操作。详细地说:只要当nCTS有用时(标明接纳方的FIFO现已准备安排妥当来接纳数据了由于接纳端的nRTS是和发送端的nCTS衔接的nCTS有用也就标明接纳端的nRTS有用也就标明接纳方的FIFO现已准备好接纳数据啦),UART才会将FIFO中的数据发送出去。在UART接纳材料之前,只需当接纳FIFO有至少2-byte空余的时分,nRTS就会被置为有用。图5-12是UART 主动流控形式的衔接方法
图5-12
中止/DMA恳求发生
S3C2410的每个UART都有7种状况,分别是:溢出掩盖(Overrun)过错、奇偶校验过错、帧犯错、断线过错(暂停态)、接纳安排妥当(接纳缓冲区准备好)、发送缓冲闲暇、发送移位器闲暇。它们在UART状况寄存器 UTRSTATn / UERSTATn 中有相应的标志位。
波特率发生器
每个UART操控器都有各自的波特率发生器来发生发送和接纳材料所用的序列时钟,波特率发生器的时钟源能够由CPU内部的体系时钟(PCLK),也能够从CPU的 UCLK (外部UART设备的时钟)管脚由外部获得时钟信号,而且能够经过 UCONn 挑选各自的时钟源。
波特率发生的详细计算方法如下:
当挑选CPU内部时钟(PCLK)时:
UBRDIVn=(int)(PCLK/(bps*16))-1,bps为所需求的波特率值,PCLK为CPU内部外设总线(APB)的作业时钟。
当需求得到更准确的波特率时,能够挑选由 UCLK 引进的外部时钟来生成。
UBRDIVn=(int)(UCLK/(bps*16))-1
LoopBack操作形式:
S3C2410 CPU的UART供给了一种测验形式,也便是这儿所说的LoopBack形式。在规划体系的详细应用时,为了判别通讯毛病是由于外部的数据链路上的问题,仍是CPU内驱动程序或CPU自身的问题,这就需求选用LoopBack形式来进行测验。在LoopBack形式中,材料发送端TXD在UART内部就从逻辑上与接纳端RXD连在一起,并能够来验证材料的收发是否正常。
UART操控寄存器
下面将针对UART的各个操控寄存器逐个进行解说,以期对UART的操作和设置能有更进一步的了解。
ULCONn (UART Line Control Register)见图5-13
图5-13
Word Length :决议每帧的数据位数
Number of Stop Bit :中止位数
Parity Mode :奇偶校验位类型
Infra-Red Mode :UART/红外形式挑选(当以UART形式作业时,需设为“0”)
UCONn (UART Control Register)见图5-14
Receive Mode :挑选接纳形式。假如是选用DMA形式的话,还需求指定说运用的DMA信道。
Transmit Mode :同上。
Send Break Signal :挑选是否在传送一帧数据半途发送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
Clock Selection :挑选UART波特率发生器的时钟源。
图5-14
UFCONn (UART FIFO Conrtol Register)用于对收发缓冲的办理,包含缓冲的触发字节数的设置,FIFO的使能见图5-15
FIFO Enable :FIFO使能挑选。
Rx FIFO Reset :挑选当复位接纳FIFO时是否主动铲除FIFO中的内容。
Tx FIFO Reset :挑选当复位发送FIFO时是否主动铲除FIFO中的内容。
Rx FIFO Trigger Level :挑选接纳FIFO的触发水平。
Tx FIFO Trigger Level :挑选发送FIFO的触发水平。
图5-15
UMCONn (UART Modem Control Register)见图5-16
Request to Send :假如在AFC形式下,该位将由UART操控器主动设置;不然的话就有必要由用户的软件来操控。
Auto Flow Control :挑选是否使能主动流控(AFC)。
图5-16
UTRSTATn (UART TX/RX Status Register)见图5-17
Receive buffer data ready :当接纳缓冲寄存器从UART接纳端口接纳到有用材料时将主动置“1”。反之为“0”则标明缓冲器中没有材料。
Transmit buffer empty :当发送缓冲寄存器中为空,主动置“1”;反之标明缓冲器中正有材料等候发送。
Transmitter empty :当发送缓冲器中现已没有有用材料时,主动置“1”;反之标明尚有材料未发送。
图5-17
UERSTATn (UART Error Status Register)见图5-18
Overrun Error :为“1”,标明发生Overrun过错。
Frame Error :为“1”。标明发生Frame(帧)过错。
图5-18
UFSTATn :(UART FIFO Status Register)见图5-19
Rx FIFO Count :接纳FIFO中当时寄存的字节数。
Tx FIFO Count :发送FIFO中当时寄存的字节数。
Rx FIFO Full :为“1“标明接纳FIFO已满。
Tx FIFO Full :为“1“标明发送FIFO已满。
图5-19
UMSTATn :(UART FIFO Status Register)见图5-20
Clear to Send :为“0”标明CTS无效;为“1”标明CTS有用。
Delta CTS :指示自从前次CPU拜访该位后,nCTS的状况有无发生改动。
为“0”则阐明不曾改动;反之标明nCTS信号现已变化了。
图5-20
UTXHn 和 URXHn 分别是UART发送和接纳材料寄存器
这两个寄存器寄存着发送和接纳的材料,当然只要一个字节8位材料。需求留意的是在发生溢犯过错的时分,接纳的材料有必要要被读出来,不然会引发下次溢犯过错
UBRDIVn :(UART Baud Rate Divisor Register)见图5-21
图5-21
接着咱们经过结合代码来看看详细在程序中怎样来操作UART的流程:
先来看看在C代码中对用到的UART多个寄存器的界说:
#define UART_CTL_BASE 0x50000000 //UART0的寄存器的开始地址也便是ULCON0的地址
#define UART0_CTL_BASE UART_CTL_BASE
#define bUART(x, Nb) __REGl(UART_CTL_BASE + (x)*0x4000 + (Nb)) //由于考虑到UART1与UART0相应的寄存器地址相差0x4000所以这儿也考虑到了对UART1和UART2的运用,而上面__REGl的界说:
#define __REG(x) (*(volatile unsigned long *)(x))
#define __REGl(x) __REG(x)
#define bUARTb(x, Nb) __REGb(UART_CTL_BASE + (x)*0x4000 + (Nb)) //#define __REGb(x) (*(volatile unsigned char *)(x))
#define oULCON 0x00
#define oUCON 0x04
#define oUFCON 0x08
#define oUMCON 0x0c
#define oUTRSTAT 0x10
#define oUERSTAT 0x14
#define oUFSTAT 0x18
#define oUMSTAT 0x1c
#define oUTXHL 0x20
#define oUTXHB 0x23
#define oURXHL 0x24
#define oURXHB 0x27
#define oUBRDIV 0x28
#define ULCON0 bUART(0, oULCON)
#define UCON0 bUART(0, oUCON)
#define UFCON0 bUART(0, oUFCON)
#define UMCON0 bUART(0, oUMCON)
#define UTRSTAT0 bUART(0, oUTRSTAT)
#define UERSTAT0 bUART(0, oUERSTAT)
#define UFSTAT0 bUART(0, oUFSTAT)
#define UMSTAT0 bUART(0, oUMSTAT)
#define UTXH0 bUART(0, oUTXHL)
#define URXH0 bUART(0, oURXHL)
#define UBRDIV0 bUART(0, oUBRDIV)
#define UTRSTAT_TX_EMPTY (1 << 2)
#define UTRSTAT_RX_READY (1 << 0)
#define UART_ERR_MASK 0x0f
再来看看真正对UART的操作:
void init_uart(void)
{
ULCON0 = vULCON0; //#define vULCON0 0x03 标明每帧有8个数据位,1个中止位,不进行奇偶校验,正常形式
UCON0 = vUCON0; //#define vUCON0 0x245 标明接纳形式和发送形式都是中止或轮询形式,当发生接纳反常时,发生接纳过错中止,发送中止类型为Level,接纳中止类型为Pulse,波特率时钟源为PCLK
UFCON0 = vUFCON0;
UMCON0 = vUMCON0;
UBRDIV0 = 12;
}
void putc(char c)
{
char i;
while (!(UTRSTAT0 & UTRSTAT_TX_EMPTY)) { //不断的查询,直到发送缓冲寄存器和和移位寄存器都不为空,就能够发送数据
;
}
for (i=0; i<10; i++) {
;
}
UTXH0 = c; //直接即将发送的字符赋值给发送寄存器发送出去
}
unsigned char getc(void)
{
while (!(UTRSTAT0 & UTRSTAT_RX_READY)) {
;
}
return URXH0; //直接从接纳寄存器中回来接纳到的1个字节的数据
}