历史上的今天
返回首页

历史上的今天

今天是:2025年06月14日(星期六)

2020年06月14日 | s3c2440的uart知识点

2020-06-14 来源:eefocus

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?imageView2/2/w/550?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,

推荐阅读

史海拾趣

Gilway Technical Lamp公司的发展小趣事
定期清洁冰箱内外表面和门封条,保持清洁卫生。
Connection One公司的发展小趣事

在电子行业的初期,Connection One公司凭借其创始人对半导体技术的深刻理解,成功研发出一款具有划时代意义的芯片。这款芯片不仅性能卓越,而且功耗极低,立即在市场上引起了轰动。公司因此迅速积累了第一笔资金,为后续的研发和扩展打下了坚实基础。

ebm-papst公司的发展小趣事

为了更好地服务中国市场,ebm-papst在中国不断推进本地化生产。公司在上海和西安设立了研发中心和生产基地,配备了与德国同样先进的实验设备。这些本地化生产和研发设施使得ebm-papst能够更快地响应中国市场的需求,提供更符合当地市场特点的产品和解决方案。同时,本地化生产也降低了公司的生产成本,提高了产品的竞争力。

Gulf Semiconductor公司的发展小趣事

随着产品种类的不断增加和生产规模的扩大,ebm-papst面临着越来越大的内部物流挑战。为了优化内部物流流程、提高生产效率,公司引入了先进的物流管理系统和自动化设备。这些措施使得公司能够更高效地管理库存、运输和配送等环节,减少了生产成本和时间成本。同时,优化内部物流也提高了产品的质量和可靠性,增强了客户对ebm-papst的信任度。

AMS公司的发展小趣事

随着产品种类的不断增加和生产规模的扩大,ebm-papst面临着越来越大的内部物流挑战。为了优化内部物流流程、提高生产效率,公司引入了先进的物流管理系统和自动化设备。这些措施使得公司能够更高效地管理库存、运输和配送等环节,减少了生产成本和时间成本。同时,优化内部物流也提高了产品的质量和可靠性,增强了客户对ebm-papst的信任度。

Ho Chien Electronics Group Inc公司的发展小趣事

为了更好地服务中国市场,ebm-papst在中国不断推进本地化生产。公司在上海和西安设立了研发中心和生产基地,配备了与德国同样先进的实验设备。这些本地化生产和研发设施使得ebm-papst能够更快地响应中国市场的需求,提供更符合当地市场特点的产品和解决方案。同时,本地化生产也降低了公司的生产成本,提高了产品的竞争力。

问答坊 | AI 解惑

SIM卡座PCB封装(抽屉式和推拉式)

SIM卡座PCB封装(抽屉式和推拉式)…

查看全部问答>

卢二都

嘿嘿,麻烦大家给我提供74HC14施密特整形电路的一些资料。谢谢…

查看全部问答>

关于LED电源驱动芯片

大家懂电源的朋友可以关心一下的,现最好的驱动电源使用哪种芯片,推荐一下!…

查看全部问答>

有害气体环境中的使用

本人 DIY各类数字湿度传感器在有害气体环境中的使用,其使用和寿命如何,对sh21的性能还无数据…

查看全部问答>

NorFlash应用问题(39VF1601型号)

1)NorFlash可供使用的地址空间应该从0x0000开始吧。那么为什么在手册中在说明ID读取时,如下:manufacturer\'s ID   0000H(address)   00BFH(data) ; Device ID   0001H(address)  2782H(data) 。感到不 ...…

查看全部问答>

我的6410裸奔和使用wince6.0哪个难度大?

我的系统主要是对来自camera接口的数据进行图像处理,并通过USB OTG口(作为device使用)上传给PC机。不需要运行其它进程。 硬件选用s3c6410。经过在s3c2442的PDA上跑图像处理测试代码,时间比较紧张,主要瓶颈在存储器访问上。因此我们打算给6410 ...…

查看全部问答>

单片机驱动H桥电路。。。。知者请 进!

我想 直接用单片机控制H桥电路,不 知道可不可以?…

查看全部问答>

各位达人,请教一个lwip的消息的类型的问题?

enum tcpip_msg_type { #if LWIP_NETCONN   TCPIP_MSG_API, #endif /* LWIP_NETCONN */   TCPIP_MSG_INPKT, #if LWIP_NETIF_API   TCPIP_MSG_NETIFAPI, #endif /* LWIP_NETIF_API */   TCPIP_MSG_ ...…

查看全部问答>

IAR4.2能修改缩进吗?

最近用IAR4.2开发ST,发现它默认的缩进只有两个空格,像 if(a) { ? ?b; } 不知道能不能修改成默认有更多空格,比如四个,像 if(a) { ? ? ? ? b; } 求教!…

查看全部问答>

430 能进行指数运算吗?

430 能进行指数运算吗? 如果能该怎样实现?? #include <math.h> void main(void) { dou××e i; i=exp(1.5); } 但从 watch 中检测 i 值 ,显示 un××iala××e 怎么一回事?? 3ks…

查看全部问答>