本文章主要参考了TI的UART用户向导文档(SPRUFM6C)。
UART是英文Universal Asynchronous Receiver/Transmitter的缩写,翻译成中文就是通用异步收发器。
首先,我们从UART的名字入手解读下UART。Universal翻译成中文就是通用(不是美国通用电气、通用汽车哈^_^),也就是普遍使用,公共使用的意思,说明这个东东不是OMAP系列芯片甚至TI所特有的。Asynchronous即异步,即发送方或者接受方(这根据UART是作为发送端还是接收端决定)与UART不需要使用同一时钟源。在异步传输中,传输的单位通常是字符,而异步传输使用的不同时钟意味着传输的字符必然有起始位和停止位。Receiver/Transmitter意味着UART既可以作为数据的接收端,也可以作为数据的发送端。
以上便是从UART这个名字中能得到的信息,下面我们把目光移向TI的文档。
OMAP-L138上提供了3组UART:UART0,UART1和UART2。而在合众达设计的DEC138开发板上只引出了UART0和UART2。
UART主要是用于串并数据的转换,也就是从外部设备接收串行数据,UART将数据转换成并行数据转发给CPU,或者是从CPU接收并行数据,并将之转换为串行数据转发给外部设备。
下图便是UART的框图:
从这个框图中我们可以看出,UART的构成要素有发送器,接收器,同步FIFO(发送器FIFO和接收器FIFO),波特率发生器等等。
一、波特率发生器
UART上的波特率发生器是可编程的,以产生不同的波特率,匹配不同的串口通信速率。波特率发生器的时钟BCLK和UART的时钟频率有关系式:BCLK = UART CLOCK/Divisor。其中,Divisor是分频数,其大小由两个8位寄存器DLH和DLL决定(DLH为高8位,DLL则为低8位,所以可以做到1-65535分频),DLL和DLH的值的加载必须在UART初始化期间完成。而所产生的波特率大小是BCLK大小的13倍或者是16倍(具体是13还是16由MDR寄存器的OSM_SEL位决定,该位为1则是13倍,为0则是16倍),那么波特率大小与UART时钟频率就有如下关系式:
波特率即是每秒钟传输的数据位数(在数据未压缩的情况下),那么由前面的我们不难得到每13个或16个BCLK时钟周期,UART将接收或发送一个数据位。UART发送一个数据位的时候必须持续13个或16个BCLK时钟周期,而当UART接收一个数据位时,它是在第6个(对应13)或第8个(对应16)BCLK时钟周期对该数据位采样。
二、操作模式
如前所述,UART可以作为发送器,也可以作为接收器。按照使用FIFO与否,UART的工作模式可以分为FIFO模式和非FIFO模式。下图是关于UART收发的四个信号:
为了对比将UART的发送器和接收器相似却又有差异的地方用相同的标号标出:
①UART的发送器部分包括THR和TSR寄存器,当UART工作在FIFO模式下时,THR是一个16字节的FIFO。
②THR从内部数据总线接收接收数据,在TSR准备就绪过后,UART将把数据从THR搬移到TSR,并串行化TSR中的数据传输到UARTn_TXD引脚。
③在非FIFO模式下,THR为空且IER寄存器中的THRE(THR empty)中断使能时将产生一个中断。当THR加载完一个字符或者IIR寄存器被读过后,该中断将被清除。
④在FIFO模式下,发送器FIFO为空将触发该中断,而该FIFO加载至少一个字节或IIR被读过后该中断将被清除。
⑤发送数据的格式:1个起始位 + 5-8个数据位 + 1个校验位(可选)+ 1,1.5或2个停止位。
以下是接收器部分:
①UART的接收器部分包括RBR和RSR寄存器,当UART工作在FIFO模式下时,RBR是一个16字节的FIFO。
②RSR从UARTn_RXD引脚接收数据位,RSR将接收到数据位连接起来,并将得到的结果传输给RBR(或接收器FIFO)。
③在非FIFO模式下,当一个字符加载到RBR中且IER寄存器中的Reciver data-ready中断使能时,将产生一个中断。当该字符被读过后,该中断将清除。
④在FIFO模式下,接收器FIFO达到设定的触发水平过后将触发该中断,而处于触发水平下过后将清除该中断(触发水平的具体值的设定是依靠FIFO control register即FCR寄存器的)。
⑤接收数据的格式:1个起始位 + 5-8个数据位 + 1个校验位(可选)+ 1个停止位(多余的停止位将被忽略而不检测)。
以上无论发送或接收数据的格式都是由LCR寄存器控制的。
三、UART的重置和初始化
1.重置:
分为硬重启和软重启,硬重启即让整个处理器的RESET引脚有效,UART也将重置,其寄存器的值也将全部恢复到默认值。软重启由PWREMU_MGMT寄存器(power and emulation management register)控制重启发送器或接收器。其中UTRST位控制着发送器,为0则发送器重置;URRST位控制着接收器,为0则接收器重置。软重启将不会影响UART内的寄存器的值。
2.初始化:
①配置PINMUX,使需使用的UART的引脚有效;
②设置波特率即配置DLH:DLL寄存器的值;
③若使用到FIFO模式,向FCR寄存器中相应的位写入所想要的触发水平值。在配置FCR的任何位之前,必须先将FCR寄存器的FIFOEN位置1;
④设置LCR寄存器,以得到想要的数据传输格式;
⑤配置MCR寄存器,如果需要autoflow控制的话;
⑥将PWREMU_MGMT寄存器的UTRST和URRST位置1以使能发送器和接收器,配置PWREMU_MGMT寄存器的FREE位。
四、BSL中UART相关的函数(由于源码较多就不贴代码了)
1. uint32_t UART_init(uart_regs_t *uart, uint32_t baud_rate)
初始化指定的UART(具体初始化了哪些东东可以参见函数内的具体语句和上面介绍的UART初始化过程),并设置其工作的波特率位baud_rate。
2. uint32_t UART_txByte(uart_regs_t *uart, uint8_t in_data)
利用指定UART发送一个字符in_data。
3. uint32_t UART_txArray(uart_regs_t *uart, uint8_t *in_data, uint32_t in_length)
调用函数UART_txByte(),利用指定UART发送一个长度为in_length的字符串in_data。
4. static uint32_t getStringLength(char *in_string)
计算指定字符串in_string的字符个数。
5. uint32_t UART_txString(uart_regs_t *uart, char *in_data)
调用函数UART_txArray()和getStringLength(),利用指定UART,发送一个任意长度的字符串in_data。
6. uint32_t UART_txUint8(uart_regs_t *uart, uint8_t in_data)
利用函数UART_txArray()将8位无符号数in_data按16进制输出,即按“0X…”的形式输出。
7. uint32_t UART_txUint32(uart_regs_t *uart, uint32_t in_data)
利用函数UART_txArray()将32位无符号数in_data按16进制输出,即按“0X…”的形式输出。
8. uint32_t UART_rxByte(uart_regs_t *uart, uint8_t *data)
从指定的UART接收字符data。