UART接口

来源:互联网 发布:agile软件 编辑:程序博客网 时间:2024/05/16 10:48

本文转自:http://blog.chinaunix.net/uid-24148050-id-170849.html

1.UART


    UART(Universal Asynchronous Receiver and Transmitter)通用异步收发器(异步串行通信口),是一种通用的数据通信协议,它包括了RS232、RS499、RS423、RS422和RS485等接口标准规范和总线标准规范,即UART是异步串行通信口的总称。
   而RS232、RS499、RS423、RS422和RS485等,是对应各种异步串行通信口的接口标准和总线标准,它规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容,这些东东都是物理层的概念。
   通信协议,是属于通信网络中的数据链路层的概念。

1.1 RS232


    COM口是PC(个人计算机)上,异步串行通信口的简写。由于历史原因,IBM的PC外部接口配置为RS232,成为实际上的PC界默认标准。所以,现在PC机的COM口均为RS232。
   
  上图最右边的是串口接口,统称为RS232接口(封装DB9)
  通信过程中实际只有两个管脚参与通信
    2脚:电脑的输入RXD 
    3脚:电脑的输出TXD 
    
    5脚:接地
  通过2,3脚就实现全双工(可同时收发)的串行异步通信

1.2 UART通信协议

 
    UART使用的是 异步,串行通信。
    串行通信是指利用一条传输线将资料一位位地顺序传送。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。
    异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的。
    数据传送速率用波特率来表示,即每秒钟传送的二进制位数。例如数据传送速率为120字符/秒,而每一个字符为10位(1个起始位,7个数据位,1个校验位,1个结束位),则其传送的波特率为10×120=1200字符/秒=1200波特。
    数据通信格式如下图:


其中各位的意义如下:
    起始位:先发出一个逻辑”0”信号,表示传输字符的开始。
    数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。小端传输
    校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验)
    停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
    空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。

    注:异步通信是按字符传输的,接收设备在收到起始信号之后只要在一个字符的传输时间内能和发送设备保持同步就能正确接收。下一个字符起始位的到来又使同步重新校准(依靠检测起始位来实现发送与接收方的时钟自同步的)



3. Uboot 串口驱动

  1. board_init_r()
  2.     --》devices_init()
  3.         --》drv_system_init()
  4.             创建串口设备 serial,放到全局数组devlist[]中去
  5.              struct device_t serial{
  6.                 .name = "serial"
  7.                 .putc= serial_putc; //这些函数是芯片相关的
  8.                 .puts= serial_puts;
  9.                 .getc= serial_getc;
  10.                 .gets= serial_gets;
  11.             }
  12.         --》console_init_r()
  13.             --》设置钩子函数,这些函数是硬件相关的
  14.                 gd->jt[XF_getc]= serial_getc;
  15.                 gd->jt[XF_tstc]= serial_tstc;
  16.                 gd->jt[XF_putc]= serial_putc;
  17.                 gd->jt[XF_puts]= serial_puts;
  18.                 gd->jt[XF_printf]= serial_printf;
  19.             --》在devlist[]中搜索,初始化标准输入,标准输出和错误输出的device_t指针
  20.                 inputdev = search_device (DEV_FLAGS_INPUT, "serial");
  21.                 outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
  22.                 errdev = search_device (DEV_FLAGS_OUTPUT, "serial");
  23.             --》文件描述符file_no与设备device_t绑定,初始化stdio_devices[file_no]= dev
  24.                 console_setfile (stdout, outputdev);
  25.                 console_setfile (stderr, errdev);
  26.                 console_setfile (stdin, inputdev);

Uboot中,串口打印流程

  1. printf-->puts-->fputs

  2. void fputs (int file,const char *s){
  3.     if (file< MAX_FILES)
  4.         stdio_devices[file]->puts(s);
  5.         //调用的函数为serial_puts,芯片相关不分析
  6. }

4. Linux串口驱动


  1. start_kernel()
  2.     --> console_init()
  3.         -->cpm_uart_console_init()
  4.             -->register_console(&cpm_scc_uart_console)
  5.                 console->setup()
  6.                 //最终调用cpm_uart_cnsole_setup()
  7.                 //初始化uart控制器,并将console 结构加入到 console_drivers 列表中去
    注意,
    由于我们在console_init中调用cpm_uart_console_init时,
    因为当时uart port的基址等基本参数都没有确立, 故其中调用console->setup 以失败返回,
    即调用register_console 没有成功注册,

    故后面在do_initcalls中调用 cpm_uart_init()进行初始化时,
    其初始化中调用uart_configure_port会再次调用register_console
    这次由于uart port的基址等参数得到初始化,故register_console成功

  1. do_initcalls()
  2.     -->cpm_uart_init()                
  3.         -->uart_register_dirver(&cpm_reg)

  4.         for( i=0; i< cpm_uart_nr; i++)
  5.             con = cpm_uart_port_map[i]
  6.             -->uart_add_one_port(&cpm_reg,&cpm_uart_ports[con].port)
  7.                //行参(struct uart_driver *drv, struct uart_port *port)
  8.                 注意这里有 port->cons= drv->cons;
  9.                 -->uart_configuare_port(drv, state, port)
  10.                     --> port->ops->config_port(port, flags)        
  11.                     //这里port的ops是 cpm_uart_pops
  12.                     //即调用cpm_uart_config_port, 初始化buf,bd,controlller,enable rx/tx
  13.                         --> cpm_uart_request_port(port)
  14.                             cpm_uart_allocbuf(pinfo,0)
  15.                             cpm_uart_initbd(pinfo)
  16.                             cpm_uart_init_scc(pinfo)
  17.                     -->uart_report_port(drv,port)    //打印串口相关信息
  18.                     -->register_console(port->cons)    //形参(struct console *console)
  19.                         //加入到 console_drivers 列表中去
  20.                     -->uart_console(port)

printk在src/kernel/printk.c中实现

  1. int printk(constchar *fmt,...)
  2.     static char printk_buf[1024];    
  3.     // 函数内申请了一块静态内存printk_buf[]作为format缓冲区,然后把缓冲区内容放到LOG_BUF中
  4.     // 不管console是否存在,printk都成功返回。
  5.     --> release_console_sem();
  6.         --> call_console_drivers();
  7.             -->_call_console_drivers(start_print, cur_index, msg_level);
  8.                 // 对console驱动中write的调用
  9.                 for (con = console_drivers; con; con= con->next){
  10.                  if ((con->flags& CON_ENABLED) && con->write)
  11.                  con->write(con,&LOG_BUF(start), end- start);
  12.                 }

  13.         con->write() 实际上是 cpm_scc_uart_console.write
  14.         即 cpm_uart_console_write()
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 听力正常体检不过关怎么办 做完人流第二天同房了怎么办 医院的票据丢了怎么办 体检人体成分(脂肪缺乏)该怎么办 诊断出右下叶肺炎怎么办 做胸透穿钢圈内衣怎么办 预约不上留学体检怎么办 跨省离职后社保怎么办 开车到成都限号怎么办 月经量多怎么办吃什么 报驾校体检视力不达标怎么办 换驾驶证c1一只眼不合格怎么办 考驾照紧张腿抖怎么办 驾照该换了色弱怎么办 怀孕5个月感冒咳嗽怎么办 怀孕4个月喉咙痛怎么办 怀孕5个多月总是咳嗽尿失禁怎么办 怀孕7个月感冒了怎么办 怀孕7个月感冒喉咙痛怎么办 孕38周感冒咳嗽喉咙痛怎么办 嗓子痛咳嗽有痰怎么办 怀孕6个月了咳嗽怎么办 怀孕了咳嗽黄痰怎么办 科二5次没考过怎么办 交警开的罚单丢了怎么办 驾驶员从业资格证被水洗了怎么办 驾照考五次没过怎么办 学车每次考不过怎么办 年检超期3个月怎么办 年检超过3个月怎么办 工商执照年检时候忘记密码怎么办 个体工商营业执照年检过期怎么办 忘了审车时间怎么办 汽车年检超过时间了怎么办 星巴克金星会员到期怎么办 驾考学员证丢了怎么办 违章扣满12分怎么办 违章扣满12分后怎么办 东方时尚驾校科二考不过怎么办 东方时尚科二科三考五次没过怎么办 不想考科目三了怎么办