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
位的内容是: ![](https://img-blog.csdnimg.cn/20190225202542290.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MTgxODEx,size_16,color_FFFFFF,t_70) Uart调制解调器控制寄存器:UART MODEM CONTROL REGISTER
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都有一个8位的数据缓冲区:
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, = 0xFFFFFFFE
str 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, #0
ldr r0, [r1]
str r1, [r1]
ldr r2, [r1]
cmp r1, r2
ldr sp, =0x40000000+4096 @先默认是nor启动
moveq sp, #4096
streq r0, [r1] @修改了的值,要在这里恢复
/***
真正运行的内容,前面都是初始化的东西:clock、nor/nand的选择
***/
/* 设置内存: sp 栈 */
@ldr sp, =4096 /* nand启动,先不执行这一行代码 */
//ldr sp, =0x40000000+4096 /* nor启动 */
/* 调用main */
bl main
halt:
b halt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
main.c
#include"s3c2440_soc.h"
#include"uart0.h"
#define uchar unsigned char
int main()
{
uart0_init();
putString("this is uart0n"); // 先打印出来
uchar tmp;
while(1){
tmp = (uchar) getchar(); //这就是重复打印了
putchar(tmp);
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
uart0.c:
#include"s3c2440_soc.h"
#include"uart0.h"
/***
使用引脚,GPH2——txd0 GPH3——rxd0
用PCLK(100m)作为时钟源、normal模式,无中断,非fifo,非AFC,
上一篇:s3c2440串口接收中断(OK2440III)
下一篇:s3c2440串口详解
推荐阅读最新更新时间:2024-11-11 06:28