CORTEX-A8裸机系列:第十一章 串口

第十一章 串口

这部分代码,查看我的github网址:https://github.com/weiqi7777/s5pv210

1、210的UART控制器

210提供了4个UART,4个UART可以工作在中断或者DMA模式。串口能产生中断或者DMA请求数据传输信号。UART支持最大比特率3Mbps。每个UART包含了两个FIFO,用来接收和发送数据。

对于ch0,有256字节fifo,对于ch1,有64字节fifo,对于ch2和ch3,有16字节fifo。

UART包括一个波特率产生器,发送器,接收器和控制单元。


时钟源可以有两个选择,PCLK和SCLK_UART。

当数据写入到发送FIFO,硬件会自动的将数据拷贝到发送移位器中,然后通过发送管脚(TXDN)一位一位发送出去。

当从接收移位器从接收数据管脚(RXDN)中接收到数据后,会将该数据拷贝到接收FIFO中。

2、自动流控(AFC,auto flow control)

解决发送方和接收方之间数据传输不一致导致数据丢失的情况,因此加了几个信号,实现流控制。

对于发送方,要发送数据的时候,要将一根控制线拉高,接收方接收到该控制信号为高,表示要接收数据。

对于接收方,可以接收数据的时候,将一根控制线拉高,发送方接收到该控制信号为高,表示可以发送数据。

所以,流控的目的是使串口通信变得可靠,在发送方速率比接收方快的时候,流控可以保证发送和接收均不会漏掉数据。不过,现在已经不使用该功能了。

3、IrDA模式及其用法

1) IrDA其实就是红外,红外就是红外线通信(电视机,空调遥控器就是红外通信)。

2) 红外编码传输和串口传输很类似,按照一定时间,发送红外,有发送红外线,表示传输1,没有发送红外线,表示传输0。

3) 红外通信的原理:发送方固定间隔时间向接收方发送红外信号(表示1或0)或者不发送红外信号(表示0或1),接收方每隔固定时间去判断有无红外线信号来接收1和0。

4) 因此红外通信和串口通信很类似,都是每隔固定时间发送1或者0(判断1或0的物理方式不同)给接收方来通信。因此,210就利用串口通信来实现了红外发送和接收

5) 210的某个串口支持IrDA,开启红外模式后,我们只需要向串口写数据,这些数据就会以红外光的方式向外发射出去(当然是需要一些外部硬件支持),然后接收方接收这些红外数据即可解码得到我们的发送信息。

4、串口中断

串口中断,有三类

1) 接收中断,当接收到数据,并接收数据达到FIFO的触发数目,产生中断

2) 发送中断,方发送数据,FIFO中的数据小于或等于FIFO的触发数目,产生中断。

3) 错误中断,传输发生一些其他错误,产生中断


对于发送,有一个状态寄存器,其中有一位叫做发送缓冲器空标志,发送器发送完成((发送缓冲区空了)就会给这个标志位置位,CPU就是通过不断查询这个标志位为1还是0来知道发送是否已经完成。

对于接收,有一个状态寄存器,其中有一位叫做接收缓冲器满标志,CPU通过不断查询这个标志位判断是否接收到数据。但是这样,效率就很低了,因此,对于接收,要使用中断的模式。

5、波特率设置

串口,有一个很重要的东西,就是波特率的设置。波特率如果设置的不正确,那么串口通道是不能正常通信的。

波特率设置,有两个重要寄存器,UBRDIVn和UDIVSLOTn。其中UBRDIVn为主要波特率设置的寄存器,UDIVSLOTn为辅助的寄存器,目的是为了校准波特率。

计算公式如下:


关于UDIVSLOTn,推荐的值


我们写程序的时候,就使用手册上推荐的参数,设置波特率就行了。

6、串口初始化

6.1、将串口管脚设置为串口功能

设置GPA0CON寄存器,将GPIO设置为串口功能。



6.2、设置串口功能的关键寄存器

UCONx, ULCONx, UMCONx, UFCONx, UBRDIVx, UIDVSLOTOx。

对于UCONx(867页),设置串口的数据传输的格式。包括数据位,停止位,奇偶校验位,以及工作模式。


对于ULCONx,设置串口的发送和接收工作模式,以及时钟源选择和一些其他设置。



对于UFCONx,设置关于FIFO的功能。


对于UMCONx,设置关于流控和modem功能。


对于UBRDIVx, UIDVSLOTOx寄存器(878页),设置波特率。



6.3、读取串口发送接收状态

状态保存在UTRSTAT寄存器中。

发送的时候,有两个信号,一个是Transmitter empty ,一个是transmitter buffer empty。两个在没有使用FIFO的时候,效果是一样的,但是如果使用FIFO的话,就要使用transmitter buffer empty。

Transmitter empty是包括传输的FIFO和传输的移位寄存器,两个都为空,这一位的值才会为1。

Transmitter buffer empty只是指FIFO,当FIFO空的时候,该位才为1。所以当使用串口FIFO功能的时候,要检测这一位,判断发送是否完成。

当Receive buffer data ready为1,表示接收到数据。


6.4、发送数据

直接往寄存器UTXH写入值即可。但是前提是发送FIFO,没有满。因此在写入之前,需要判断FIFO是否满。

6.5、读取数据

直接读取寄存器URXH即可。但是前提是接收FIFO中有数据。因此在读取之前,需要判断FIFO是否为空。

7、移植stdio

printf函数和scanf函数可以和底层输入、输出函数绑定,然后这两个函数就可以和stdio绑定起来。也就是直接调用printf函数输出,内容就会从标准输出输出出去。

因此,这个时候标准输出就不是屏幕了,而是串口。标准输入也不是键盘,而是串口。

7.1、printf函数原理

printf函数工作时内部实际调用了2个关键函数:

一个是vsprintf函数(主要功能是格式化打印信息,最终得到纯字符串格式的打印信息等待输出)

另一个就是真正的输出函数(操控标准输出的硬件,将信息发送出去)

移植printf函数可以有3个途径获取printf的实现源码:

1) 最原始最原本的来源就是linux内核中的printk。难度较大而且麻烦。

2) 从uboot中移植

3) 直接使用别人移植好的

 

使用全局变量定义了两个缓冲区,一个是接收数据用,一个是发送数据用。


最终,printf函数调用putc函数,所以要实现putc,实现数据发送。scanf函数调用getc函数,所以要实现getc。

移植,修改顶层的makefile,增加一些变量,并将变量导出,让子文件夹的makefile使用这些变量。

然后再进入到子文件夹,运行makefile。



make –C lib,就是进入到lib文件夹,执行make。lib文件夹,放的就是实现printf,scanf函数的库函数代码。将库函数编译成,静态库,然后在顶层链接到我们写的程序当中去。

7.2、printf函数

printf

    调用vsprintf

        调用vsnprintf

            调用number

vsprintf函数的作用是按照我们的printf传进去的格式化文本,对变参进行处理,然后将之格式化后缓存在一个实现分配好的缓冲区中。

printf后半段调用putc函数将缓冲区中格式化后的字符串直接输出到标准输出(也就是串口)。

此条目发表在CORTEX-A8分类目录,贴了, , 标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。