第八天: 串口通信代码实战及uart stdio 移植

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Karven_/article/details/52202064

1.S5PV210串行通信接口详解2

  1. 本来串口的功能就是上节讲过的部分,但是后来的技术发展给串口叠加了一些高级功能,在像210这类的高级SoC的串口控制器中,都有这类高级功能。
  2. FIFO模式及其作用

(1)典型的串口设计,发送/接收缓冲区只有1字节,每次发送/接收只能处理1帧数据。这样在单片机中没什么问题,但是到复杂SoC中(一般有操作系统的)就会有问题,会导致效率低下,因为CPU需要不断切换上下文。

(2)解决方案就是想办法扩展串口控制器的发送/接收缓冲区,譬如将发送/接收缓冲器设置为64字节,CPU一次过来直接给发送缓冲区64字节的待发送数据,然后transmitter慢慢发,发完再找CPU再要64字节。但是串口控制器本来的发送/接收缓冲区是固定的1字节长度的,所以做了个变相的扩展,就是FIFO。

(3)FIFO就是first in first out,先进先出。fifo其实是一种数据结构,这里这个大的缓冲区叫FIFO是因为这个缓冲区的工作方式类似于FIFO这种数据结构。

 

  1. DMA模式及其作用

(1)DMA direct memory access,直接内存访问。DMA本来是DSP中的一种技术,DMA技术的核心就是在交换数据时不需要CPU参与,模块可以自己完成。

(2)DMA模式要解决的问题和上面FIFO模式是同一个问题,就是串口发送/接收要频繁的折腾CPU造成CPU反复切换上下文导致系统效率低下。

(3)传统的串口工作方式(无FIFO无DMA)效率是最低的,适合低端单片机;高端单片机上CPU事物繁忙所以都需要串口能够自己完成大量数据发送/接收。这时候就需要FIFO或者DMA模式。FIFO模式是一种轻量级的解决方案,DMA模式适合大量数据迸发式的发送/接收时。

 

  1. IrDA模式及其用法

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

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

扫描二维码关注公众号,回复: 5811182 查看本文章

(3)分析可知,红外通信和串口通信非常像,都是每隔固定时间发送1或者0(判断1或0的物理方式不同)给接收方来通信。因此210就利用串口通信来实现了红外发送和接收。

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

 

 

 

  1. S5PC210串口通信接口详解3
    1. 串行通信与中断的关系
      1. 串口通信分为发送/接受2部分。发送方一般不需要(也可以使用)中断即可完成发送,接受方必须(一般来说必须,也可以轮询方式接收)使用中断接收
      2. 发送方可以选择使用中断,也可以选择不使用中断。使用中断的工作情景是:发送方先设置好中断并绑定一个中断处理程序,然后发送方丟一帧数据给transmittertransmitter发送耗费一段时间来发送这一帧数据,这段时间内发送方CPU可以去做别的事情,等transmitter发送完成会产生一个TXD中断,该中断会导致事先绑定的中断处理程序执行,在终端处理程序中CPU会切换回来继续给transmitter放一帧数据,然后CPU切换离开;不适用中断的工作情景是:发送方事先禁止TXD中断(当然也不需要给相应的中断处理程序了),发送方CPU给一帧数据到transmitter,然后transmitter耗费一段时间来发送这帧数据,这段时间CPU在这等着(CPU没有切换去做别的事情),待发送方发送完成后CPU再给它一帧数据继续发送直到所有数据发完。CPU是怎么知道transmitter已经发送完了?原来是有个状态寄存器,状态寄存器中有一个位叫发送缓冲区空标志,transmitter发送完成(发送缓冲区空了)就会给这个标志位置位,CPU就是通过不断查询这个标志位为1还是0来指导发送是否已经完成的。
      3. 因为串口通信是异步的,异步的意思就是说发送方占主导权。也就是说发送方随时想发就能发,但是接收方只有时刻等待才不会丢失数据。所以这个差异就导致发送方可以不用中断,而接收方不得不使用中断模式。
    2. 210串口通信的时钟设计
      1. 串口通信为什么需要时钟
        1. 因为串口通信需要一个固定的波特率,所以transmitterreceiver都需要一个时钟信号
        2. 时钟信号从哪里来?  源时钟信号时外部APB总线提供给串口提供给串口模块的(这就是为什么我们说串口是挂在APB总线上),然后进到串口控制器内部后给波特率发生器实质是一个分频器,在波特率发生器中进行分频,分频得到一个低频时钟,这个时钟就是给transmitterreceiver使用的
        3. 串口通信中时钟的设置主要是寄存器的操作,重点的有:  寄存器源设置(为串口控制器选择源时钟,一般选择为PCLK_PSYS,也可以是SCLK_UART),还有波特率发生器的2个寄存器。
        4. 波特率发生器有2个重要寄存器:UBRDIVnUBRDIVn,其中UBRDIVn是主要的设置波特率的寄存器,UDIVSLOTn是用来辅助设置的,目的是为了校准波特率的。
  2. S5PV210串行通信编程实战1
    1. 整个程序流程分析
      1. 整个串口通信相关包含两部分:uart_init负责初始化串口,uart_putc负责发送一个字节
    1. 串口控制器初始化关键步骤
      1. 初始化串口的TxRx引脚所对应的GPIOGPA0_1GPA0_0
      2. GPA0CON(0xE0200000),bit[3:0]=0b0010   bit[7:4] = 0b0010
      3. 初始化这几个关键寄存器UCON0   ULCON0 UMCON0 UBRDIVn UDIVSLOTn
      1. 主要的几个寄存器

(1)ULCON0 = 0x3                // 0校验位、8数据位、1停止位

(2)UCON = 0x5                // 发送和接收都是polling mode

(3)UMCON0 = 0x0                // 禁止modem、afc

(4)UFCON0 = 0x0                // 禁止FIFO模式

(5)UBRDIV0和UDIVSLOT0和波特率有关,要根据公式去算的

 

  1. C源文件中定义访问寄存器的宏

定义好了访问寄存器的宏之后,将来写代码时直接使用即可。

 

  1. S5PV210串行通信编程实战2

串口Tx、Rx对应的GPIO的初始化

给GPA0CON的相应bit位赋值为相应值,用C语言位操作来完成。

  1. UCON、ULCON、UMCON、UFCON等主要控制寄存器

依据上节中分析的值进行依次设置即可。

  1. 波特率的计算和设置

(1)第一步,用PCLK_PSYS和目标波特率去计算DIV_VAL: DIV_VAL = (PCLK / (bps x 16)) ?1

(2)第二步,UBRDIV0寄存器中写入DIV_VAL的整数部分

(3)第三步,用小数部分*16得到1个个数,查表得uBDIVSLOT0寄存器的设置值

  1. 串口发送和接收函数的编写

(1)写发送函数,主要发送前要用while循环等待发送缓冲区为空才能发送。

  1. 综合调试

注意Makefile的修改。

  1. 扩展练习-更改波特率后再调试

自己练习。注意程序中改了波特率后,SecureCRT也要相应修改,不然收不到东西。

 

 

  1. uart stdio 的移植1
    1. 什么是stdio?
      1. #include<stdio.h>
      2. standard input output ,标准输入输出
      3. 标准输入输出就是操作系统定义的默认的输入和输出通道。一般在PC的情况下,标准输入指的是键盘,标准输出指的是屏幕。
      4. printf scanf 函数可以和底层输入/输出函数绑定,然后这两个函数就可以和stdio绑定起来。也就是说我们直接调用printf函数输出,内容就会被标准输出输出出去。
      5. 在我们这里,标准输出当然不是屏幕了,而是串口。标准输出也不是键盘,而是串口。
    2. printf 函数的工作原理
      1. printf函数工作时内部实际调用了2个函数: 一个是vsprintf (主要功能是格式化打印信息,最终得到纯数字格式的打印信息等待输出),另一个就是真正的输出函数putc(操控标准输出的硬件,将信息发送出去)
    3. 移植printf函数的三种思路
      1. 我们希望在我们的开发板上使用printf函数进行(串口)输出。使用scanf函数进行(串口)输入,就像在PC机上键盘和屏幕进行输入输出一样。因此需要移植printf函数/scanf函数
      2. 我们说的移植不是编写,我们不希望自己完全从新编写而是想尽量借用也有的代码(叫移植)
      3. 一般移植printf函数可以有三个途径获取printf的实现源码:
        1. 最原始最原本的来源就是linux内核中的printk。难度较大、关键是麻烦;
        2. 简单一点的是从uboot中移植printf
        1. 跟简单的就是直接使用别人移植好的。
        2. 我们使用第三种方法,别人一直好的printf函数来自于友善之臂的Tiny210的裸机教程。
    4. 移植好的printf介绍
    5. uart stdio  移植 
      1. 修改Makefile进行printf移植
      2. makefilegcc的库文件介绍
      3. 多文件裸机工程及结构解析
      4. 编译运行及测试
  1. uart stdio

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/Karven_/article/details/52202064