s3c2440的uart知识点
s3c2440的uart和stm32、51的uart都是大同小异的。但是还是专门写一下。其实是自己作总结而已。(本文只是涉及uart的基本情况,程序的话,只有查询模式。fifo、中断、DMA还没学,后面可能会补上)
以下是它的特点:
s3c2440有三个独立的uart模块,都支持查询、中断模式或者DMA模式。
这三个uart都可以选择(非)fifo模式。Fifo适用于大规模数据传送,可能在DMA需要用到。
uart0和uart1可支持自动流控制(Auto Flow Control)模式,用来检测是否可用。有特殊的位的对应引脚。(但好像stm32的uart功能更多点,深入学习后作比较)
-
时钟来源和时钟频率的设定
uart的时钟源有两个选择:内部的PCLK分配的单元时钟(不管FCLK是晶振提供的,还是EXTCLK提供的),或者直接由外部EXTCLK提供的时钟频率。使用前者,uart的baud rate可以达到921.6kbps(最高),而接EXTCLK,可以达到更多的baud rate。
存储波特率的寄存器是16位的UBRDIVn ,具体应该存放的值,是如下计算的:
UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
( UART clock: PCLK, FCLK/n or UEXTCLK ) -
中断
具体的中断情况实际中是一定要用的,等到以后学了中断,再补充(后面寄存器那里,有稍微提及)。
在no-fifo mode下产生的中断(就是说,有多种error情况,但都是进入这两个interrupt里,再读取对应的位,做判断):
Rx interrupt :当数据从移位器shifter在代码的控制下,成功传给其他地区时,产生中断(这时的shifter还没有清空,需要程序清除)
Tx interrupt :当数据在代码的控制下成功地从其他地区传给shifter时,产生中断。
Error interrupt:所有报错的error都会导致中断,但是一次只能有一个。
在fifo mode下产生的中断(就是说,有多种error情况,但都是进入这两个interrupt里,再读取对应的位,做判断):
Rx interrupt :当fifo接收的数据达到溢出/触发中断标准时,产生中断。或者是没有达到溢出,但是等待了3个word的时间,仍没有收到数据。
Tx interrupt :当fifo所有待发送的数据都发送出去时,产生中断
Error interrupt:所有报错的error都会导致中断
UART除了Rx FIFO寄存器外,还有FIFO错误状态寄存器。错误状态FIFO表示其中的哪些数据具有一个错误(具体的错误就是上面写的那些frame error之类的)。只有当数据有错误时,才会发出错误中断,准备好读出来了。要清除错误状态FIFO,必须读出带有错误和UERSTATn的URXHn(就是上面写的那些frame error之类的) -
DMA
DMA也是很重要的,学了后要补充。 -
fifo与非fifo的区别
S3C2440A的UART内部对于接收和发送各有64字节的缓冲区,当使用FIFO模式时,UART将使用这个缓冲区进行数据暂存操作,这样可以增加数据吞吐量,提高传输速率。其实,非FIFO模式也可以看作是特殊的FIFO模式,即只有一个字节(注意,只有一个字节)缓冲区的FIFO模式。
二者的主要不同在于读取缓冲区状态的方式:非FIFO模式下,通过UTRSTAT寄存器得知收发缓冲区状态;FIFO模式下,则从UFSTAT寄存器获得缓冲区状态。要注意的是,在FIFO模式下,只有达到触发级别后才会发起Rx或Tx中断。比如说,如果设置接收触发级别为16字节,则只有在接收缓冲区中有16个字节以上数据时,才会发起Rx中断请求。如果需要进行输入回显,即是立即显示,则可能导致不能立即回显用户在串口工具中输入的字符(如果用fifo模式的话,字节数达不到中断,即回复的要求)。所以这时,就要使用非fifo模式。 -
Auto Flow Control(自动流控制)
用于通讯双方都是使用uart口时。S3C2440中的UART用nRTS(发送请求信号)和nCTS(清除发送信号)来支持自动流控制,以此实现UART之间的互联。
在AFC模式下,nRTS依赖于接收器的条件和nCTS信号控制发送器的运行。UART的发送器只当nCTS信号被激活(AFC模式下,nCTS信号意味另一个UART的FIFO已经准备好接收数据了)才发送数据到另一个UART的FIFO里。在UART接收数据的时候,当接收FIFO有大于32-byte的空闲空间时nRTS必须被激活 ,在接收FIFO的空闲空间小于32-byte(在AFC模式下,nRTS信号意味自己的接收FIFO准备好接收数据)时nRTS必须被取消激活。
UART2不支持AFC功能。 -
uart的工作流程
首先,发射器和接收器各包含64字节(不是64位,是64字节)的fifo和数据移位器。
如果是fifo,初始化uart之后,是先将数据写入FIFO,然后复制到传输移位器在传输之前。然后由传输数据pin (TxDn)将数据移出。同时,接收数据为从接收数据pin (RxDn)进行移位,然后从移位器复制到FIFO。
使用的是非fifo模式的话,其实也是用了FIFO中的一个字节的空间,作为先存进去的地方而已,不存在直接放进传输移位器的做法(如果是这样做的话,就是需要通过程序一位一位放进去了)。
接收到的数据是放到接收缓存器URXHn中,要发送数据时,是把数据放入发送缓存器UTXHn中。由于UART是通过字节方式传输数据的,因此要区分是大端模式还是小端模式,也就是说这两个寄存器在这两种模式下,读取出来的结果是不同的(有默认的情况,不修改就好了)。 -
Uart的状态和与interrupt、DMA的对应
每个uart都有7种状态信号(其实也是一些1位的寄存器位): Overrun error, Parity error, Frame error, Break, Receive buffer data ready, Transmit buffer empty, and Transmit shifter empty。分别是overrun错误,校验错误,帧错误,断点,接收缓冲区准备好,发送缓冲区为空,发送移位寄存器为空
前面四个是作为错误信号的,有相应的寄存器位,所以当这四个位被自动置1时,且中断允许位被打开,如果发生错误,就会去进入receive error status中断(硬件自身检测的),然后需要在中断子程序里代码自己去if()查询对应的位,到底是哪个error,并作出解决方案。
后面三个是作为正确信号的,通过读取,来执行下一步的程序,当然都可以进入中断。一般判断发送是否完成的是,判断Transmit buffer empty对应的那个位,因为这个位是Transmit shifter empty成立前提下,才会成立的。 -
自己之前的疑问:如果不是auto-flow的模式的话,要关闭auto-flow的位,但是, nRTS 和nCTS还要不要在程序里进行控制?
看了些资料发现是,如果不是auto-flow的模式的话,要关闭auto-flow的位,但是在fifo模式下,nRTS 和nCTS还要在程序里进行控制,非fifo不需要。
没有使用自动流控的例子(需要软件控制nRTS和nCTS)
1)使用FIFO的接收操作
选择接收模式(interrupt or DMA mode);
检查UFSTATn寄存器里的RX FIFO计数值 。假如这个值小于32,用户需要设置UMCONn[0]为‘1’(激活nRTS),如果等于或者大于32,用户需要设置这个值为‘0’(使nRTS无效);
一直重复步骤2。
2)使用FIFO的发送操作
选择发送模式(interrupt or DMA mode)
检查UMSTATn[0]的值。如果该值为‘1’(nCTS被激活),用户可以写数据到Tx FIFO寄存器
- 其余的几种模式
Loopback Mode :就是自发自收。当然,需要线来连接引脚的
Infrared (IR) mode :紫外线模式,不知道是什么。
可以看下面这个链接,感觉里面的内容是直接翻译2440手册的。
https://www.cnblogs.com/sky-heaven/p/5031783.html - 寄存器方面
Uart line控制寄存器:ULCONx(UART LINE CONTROL REGISTER )
| Register | Address | R/W | Description | Reset Value |
| ULCON0 | 0x50000000 | R/W | UART channel 0 line control register | 0x00 |
| ULCON1 | 0x50004000 | R/W | UART channel 1 line control register | 0x00 |
| ULCON2 | 0x50008000 | R/W | UART channel 2 line control register | 0x00 |
内部的位的作用:

Uart 控制寄存器(uart control register)
| Register | Address | R/W | Description | Reset Value |
| UCON0 | 0x50000004 | R/W | UART channel 0 control register | 0x00 |
| UCON1 | 0x50004004 | R/W | UART channel 1 control register | 0x00 |
| UCON2 | 0x50008004 | R/W | UART channel 2 control register | 0x00 |
位的作用:



注意的是:
FCLK Divider 这一部分的位,对于uart0、1、2是不一样的。(为什么要设置有FCLK/n这个呢,而不是全用PCLK,是考虑到APB上挂了不同的外设单元,用FCLK/n这种情况,可以有效地使各种外设得到自己合适的外设。
时钟来源选择是FCLK/n的话,是需要使用延时的:Delay(1); // about 100us
Rx/Tx Interrupt Type这两个位,类型是pulse(脉冲式)和level(电平式)。前者是as soon as,后者是while,需要等待一段时间的。
Uart的fifo控制寄存器:UART FIFO CONTROL REGISTER
| Register | Address | R/W | Description | Reset Value |
| UFCON0 | 0x50000008 | R/W | UART channel 0 FIFO control register | 0x0 |
| UFCON1 | 0x50004008 | R/W | UART channel 1 FIFO control register | 0x0 |
| UFCON2 | 0x50008008 | R/W | UART channel 2 FIFO control register | 0x0 |
| Register | Address | R/W | Description | Reset Value |
| UMCON0 | 0x5000000C | R/W | UART channel 0 Modem control register | 0x0 |
| UMCON1 | 0x5000400C | R/W | UART channel 1 Modem control register | 0x0 |
| Reserved | 0x5000800C | – | Reserved | Undef |
位的内容是:

(这个寄存器内容是关于AFC的,所以uart2没有很正常)
Uart的发送/接收状态寄存器:UART TX/RX STATUS REGISTER
| Register | Address | R/W | Description | Reset Value |
| UTRSTAT0 | 0x50000010 | R | UART channel 0 Tx/Rx status register | 0x6 |
| UTRSTAT1 | 0x50004010 | R | UART channel 1 Tx/Rx status register | 0x6 |
| UTRSTAT2 | 0x50008010 | R | UART channel 2 Tx/Rx status register | 0x6 |
位的内容:

Uart的错误情况寄存器:UART ERROR STATUS REGISTER
| Register | Address | R/W | Description | Reset Value |
| UERSTAT0 | 0x50000014 | R | UART channel 0 Rx error status register | 0x0 |
| UERSTAT1 | 0x50004014 | R | UART channel 1 Rx error status register | 0x0 |
| UERSTAT2 | 0x50008014 | R | UART channel 2 Rx error status register | 0x0 |
位的内容:
注意:该寄存器的这些位,在被读取之后会硬件自动置零。
Uart的fifo状态寄存器(只能读取):UART FIFO STATUS REGISTER
| Register | Address | R/W | Description | Reset Value |
| UFSTAT0 | 0x50000018 | R | UART channel 0 FIFO status register | 0x00 |
| UFSTAT1 | 0x50004018 | R | UART channel 1 FIFO status register | 0x00 |
| UFSTAT2 | 0x50008018 | R | UART channel 2 FIFO status register | 0x00 |
位的内容:

这个寄存器只是显示了fifo是否被填满了,以及fifo到底有多少位而已,但是还是没有透漏出fifo的物理地址。
Uart的调制器状态寄存器:UART MODEM STATUS REGISTER
| Register | Address | R/W | Description | Reset Value |
| UMSTAT0 | 0x5000001C | R | UART channel 0 modem status register | 0x0 |
| UMSTAT1 | 0x5000401C | R | UART channel 1 modem status register | 0x0 |
| Reserved | 0x5000801C | – | Reserved | Undef |
位的内容·:

Uart的发送缓冲区寄存器:UART TRANSMIT BUFFER REGISTER (HOLDING REGISTER & FIFO REGISTER)
| Register | Address | R/W | Description | Reset Value |
| UTXH0 | 0x50000020(L) 0x50000023(B) | W (by byte) | UART channel 0 transmit buffer register | – |
| UTXH1 | 0x50004020(L) 0x50004023(B) | W (by byte) | UART channel 1 transmit buffer register | – |
| UTXH2 | 0x50008020(L) 0x50008023(B) | W (by byte) | UART channel 2 transmit buffer register | – |
| UTXHn | Bit | Description | Initial State |
| TXDATAn | [7:0] | Transmit data for UARTn | – |
注意:
L是指尾端(endian)模式是小尾端模式
B是指尾端(endian)模式是大尾端模式
Uart的接收缓存区寄存器:UART RECEIVE BUFFER REGISTER (HOLDING REGISTER & FIFO REGISTER)
| Register | Address | R/W | Description | Reset Value |
| URXH0 | 0x50000024(L) 0x50000027(B) | R (by byte) | UART channel 0 receive buffer register | – |
| URXH1 | 0x50004024(L) 0x50004027(B) | R (by byte) | UART channel 1 receive buffer register | – |
| URXH2 | 0x50008024(L) 0x50008027(B) | R (by byte) | UART channel 2 receive buffer register | – |
每一个URXHn都有一个8位的数据缓冲区:
| URXHn | Bit | Description | Initial State |
| RXDATAn | [7:0] | Receive data for UARTn | – |
注意:
1—原来2440的接收buffer和发送buffer是物理上不同地区的,真是新奇。(但是只有8位吗?Fifo又有16、32之类的选择,难道是多个8位一起组成了一个fifo??)
2—当发生overrun error时,必须读取URXHn。如果没有,下一个接收到的数据也会溢出错误,尽管UERSTATn的溢出位已被清除。
Uart的baud rate寄存器:UART BAUD RATE DIVISOR REGISTER
计算公式:
UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
( UART clock: PCLK, FCLK/n or UEXTCLK )
| Register | Address | R/W | Description | Reset Value |
| UBRDIV0 | 0x50000028 | R/W | Baud rate divisior register 0 | – |
| UBRDIV1 | 0x50004028 | R/W | Baud rate divisior register 1 | – |
| UBRDIV2 | 0x50008028 | R/W | Baud rate divisior register 2 | – |
每一个寄存器对应的内容:
| UBRDIVn | Bit | Description | Initial State |
| UBRDIV | [15:0] | Baud rate division value UBRDIVn > 0 .If using the UEXTCLK as input clock,UBRDIVn can be set‘0’. | - |
以下是查询模式的程序:
start.S
.text
.global _start_start:/***关闭watchdog ****/ldr r0, = 0x53000000 @将看门狗寄存器的地址写入到r0里,将要赋的值写入r1中,并传给r0。 ldr r1, = 0 @值得说明的是,这只是关闭watchdog,不是去喂它 str r1, [r0] /***设置时钟,FCLK = 400MHz FCLK : HCLK: PCLK = 4:2:1 ****/ldr r0, = 0x4C000000 @设置locktime ldr r1, = 0xFFFFFFFEstr r1, [r0]ldr r0, = 0x4C000004 @设置MPLL的输出频率(在这里,输出频率是等于了FCLK) ldr r1, = (92<<12)|(1<<4)|(1<<0) @数值格式可能有错,没错,这样写也是16进制数,同时<<的优先级低于 | str r1, [r0]ldr r0, = 0x4C000014 @设置HCLK,PCLK ldr r1, = (1<<1)|(1<<0) str r1, [r0]mrc p15,0,r0,c1,c0,0 @因为FCLK:HCLK != 1:1,则设置异步模式 orr r0,r0,#0xc0000000 @注意数值是0xc0000000 mcr p15,0,r0,c1,c0,0/******判断是nor启动还是nand启动。相等的话,是nand启动。如果是nor启动的话, ******/mov r1, #0ldr r0, [r1]str r1, [r1]ldr r2, [r1] cmp r1, r2ldr sp, =0x40000000+4096 @先默认是nor启动 moveq sp, #4096streq r0, [r1] @修改了的值,要在这里恢复 /*** 真正运行的内容,前面都是初始化的东西:clock、nor/nand的选择 ***/ /* 设置内存: sp 栈 */@ldr sp, =4096 /* nand启动,先不执行这一行代码 *///ldr sp, =0x40000000+4096 /* nor启动 *//* 调用main */bl mainhalt:b halt
main.c
#include"s3c2440_soc.h"
#include"uart0.h"#define uchar unsigned charint main()
{uart0_init();putString("this is uart0\n"); // 先打印出来 uchar tmp;while(1){tmp = (uchar) getchar(); //这就是重复打印了 putchar(tmp);}return 0;
}
uart0.c:
#include"s3c2440_soc.h"
#include"uart0.h"
/***使用引脚,GPH2——txd0 GPH3——rxd0 用PCLK(100m)作为时钟源、normal模式,无中断,非fifo,非AFC,baud = 115200 无校验位,1位停止位、8位数据位
***/
void uart0_init()
{GPHCON &= ~( (3<<4) | (3<<6) );GPHCON |= ( (2<<4) | (2<<6) );GPHUP &= ~( (0<<2) | (0<<3) );ULCON0 = 0x00000003; //无校验位,1位停止位、8位数据位 UCON0 = 0x00000005; // 使用PCLK作为时钟源、normal模式、UFCON0 = 0; //使用的是非fifo模式UMCON0 = 0; // disable 了 自动流模式UBRDIV0 = 52; //pclk是100m,100,000,000/115200/16 = 52.25 }int putchar(int c)
{while( !(UTRSTAT0&5) ); //用 UTRSTAT0[2] 这一位更好,因为是发送缓冲区和移位器都空时,它才置1 UTXH0 = (unsigned char)c; //而UTRSTAT0[1]是缓冲区为空时,就置1
}int getchar()
{while( !(UTRSTAT0 & 1) );return URXH0;
}void putString(const char * s)
{while(*s){putchar(*s);s++;}}
Makefile:
all:arm-linux-gcc -c -o uart0.o uart0.carm-linux-gcc -c -o main.o main.carm-linux-gcc -c -o start.o start.Sarm-linux-ld -Ttext 0 start.o uart0.o main.o -o main.elfarm-linux-objcopy -O binary -S main.elf main.binarm-linux-objdump -D main.elf > main.dis
clean:rm *.bin *.o *.elf *.dis
中断、DMA、fifo等以后学到了再更。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
