六 linux UART串口驱动代分析

最新更新时间:2022-04-22来源: eefocus关键字:linux  UART  串口驱动 手机看文章 扫描二维码
随时随地手机看文章

1、对UART驱动添加设备信息


对于2440的UART,内核已经对其完整的配置不需要做写入任何的代码,


这里要说明的是,在学习的裸机的时候,我们知道,UART相应的引脚可以配置称为红外IR,这里串口2就被配置成了红外驱动。


对于平台设备,首先要说明的应该是s3c2410_uartcfg结构体,该结构体定义在,Serial_s3c.h(includelinux)文件中


structs3c2410_uartcfg {undefined


      unsigned char         hwport;   /* 硬件端口编号比如UART0  UART1 等等*/


      unsigned char         unused;  //发送和接收使能控制信号


      unsigned short        flags; //标记号


      upf_t                uart_flags;      /* 默认UART标记号,流量控制标志位*/


      unsigned int     clk_sel; //时钟选择


 


      unsigned int     has_fracval;


 


      unsigned long         ucon;      /* 对应控制寄存器UCONn*/


      unsigned long         ulcon;     /*对应格式寄存器ULCONn */


      unsigned long         ufcon;     /* 设置缓冲区的寄存器UFCONn */


};


 


在Mach-smdk2440.c (archarmmach-s3c24xx)文件中,有对其平台设备信息的描述:


static structs3c2410_uartcfg smdk2440_uartcfgs[] __initdata = {undefined


      [0] = {undefined


             .hwport       = 0,


             .flags           = 0,


             .ucon          = 0x3c5,//00000011 1100 0101


/**************************************************************************


对应的二进制为0000 0011 1100 0101


查看数据手册可以很直观的看出来,这里是设置含义是:


接收和发送均使用中断或者查询法


将发生数据帧错误时将触发中断


当使用FIFO的时候,接收超时将产生中断,设置为低电平触发中断


UART的时钟选用PCLK


*******************************************************************/


             .ulcon         = 0x03,


/**************************************************************************


对应的二进制为0000 0000 0000 0011


这里主要设设置帧格式:


8为数据位


1为停止位


无校验位


正常模式(非红外模式)


*******************************************************************/


 


             .ufcon         = 0x51,


/**************************************************************************


对应的二进制为0000 00000101 0001


这是设置使用FIFO


使能FIFO


接收FIFO的阈值为8BYTE


接收FIFO的阈值为16BYTE


*******************************************************************/


 


      },


      [1] = {undefined


             .hwport       = 1,


             .flags           = 0,


             .ucon          = 0x3c5,


             .ulcon         = 0x03,


             .ufcon         = 0x51,


      },


      /* 设备为红外模式*/


      [2] = {undefined


             .hwport       = 2,


             .flags           = 0,


             .ucon          = 0x3c5,


             .ulcon         = 0x43, //红外模式


             .ufcon         = 0x51,


      }


};


在Mach-smdk2440.c中的smdk2440_map_io函数中有:


s3c24xx_init_uarts(smdk2440_uartcfgs,ARRAY_SIZE(smdk2440_uartcfgs));(该函数定义在Init.c (archarmplat-samsung)    中),干函数又调用:


(cpu->init_uarts)(cfg,no);


cpu->init_uarts在Common.c (archarmmach-s3c24xx)文件中,指向的是s3c244x_init_uarts(该函数定义在S3c244x.c (archarmmach-s3c24xx)),然后s3c244x_init_uarts又调用s3c244x_init_uarts函数:


void __inits3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)


{undefined


      s3c24xx_init_uartdevs("s3c2440-uart",s3c2410_uart_resources, cfg, no);


}


也就是说s3c24xx_init_uarts(smdk2440_uartcfgs,ARRAY_SIZE(smdk2440_uartcfgs));最终会被使用成:


s3c24xx_init_uartdevs("s3c2440-uart",s3c2410_uart_resources, cfg, no);


也就是,UART的平台设备定义的名字为:"s3c2440-uart"


可以,应该不容忽视的是,这里内核还定义了系统的资源,s3c2410_uart_resources,该资源在Common.c (archarmmach-s3c24xx)文件中被定义:


static structresource s3c2410_uart0_resource[] = {undefined


      [0] = DEFINE_RES_MEM(S3C2410_PA_UART0,SZ_16K),


      [1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX0,


                    IRQ_S3CUART_ERR0 -IRQ_S3CUART_RX0 + 1,


                    NULL, IORESOURCE_IRQ)


};


 


static structresource s3c2410_uart1_resource[] = {undefined


      [0] = DEFINE_RES_MEM(S3C2410_PA_UART1,SZ_16K),


      [1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX1,


                    IRQ_S3CUART_ERR1 -IRQ_S3CUART_RX1 + 1,


                    NULL, IORESOURCE_IRQ)


};


 


static structresource s3c2410_uart2_resource[] = {undefined


      [0] = DEFINE_RES_MEM(S3C2410_PA_UART2,SZ_16K),


      [1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX2,


                    IRQ_S3CUART_ERR2 -IRQ_S3CUART_RX2 + 1,


                    NULL, IORESOURCE_IRQ)


};


在这里,我们以uart0的资源为例来分析一下资源的构成:


static structresource s3c2410_uart0_resource[] = {undefined


      [0] = DEFINE_RES_MEM(S3C2410_PA_UART0,SZ_16K),


      [1] =DEFINE_RES_NAMED(IRQ_S3CUART_RX0,


                    IRQ_S3CUART_ERR0 - IRQ_S3CUART_RX0 + 1,


                    NULL, IORESOURCE_IRQ)


};


可以看到对于UART0一共定义了两个资源,其中:


[0] =DEFINE_RES_MEM(S3C2410_PA_UART0, SZ_16K),表明声明的为内存资源,其实,宏DEFINE_RES_MEM被定义为:


      {                                                     


             .start = (_start),                               


             .end = (_start) + (_size) - 1,                         


             .name = (_name),                                   


             .flags = (_flags),                             


      }


其中name为NULL;也就是说,UART申请的内存资源为起始物理地址为S3C2410_PA_UART0,大小为SZ_16K,很容易可以查到S3C2410_PA_UART0对应的物理地址就是0x50000000,通过查看数据手册得到0x50000000对应的是ULCON0(UART channel 0 line controlregister,控制帧格式的寄存器)的首地址,那么为什么是SZ_16K呢?继续看数据手册,发现ULCON1的首地址是0x50004000,那么0x50004000-0x50000000=SZ_16K,所以是大小为16kBYTE;.flags = (_flags)这个标号对应的内存资源的标记号,只不过系统为每种资源设定的标记号码而已,驱动找什么类型资源就是对应这个标号找的。


补充一点的是:这里的内存资源是16Kbyte,而且申请的时候为什么只有是一个寄存器的地址,这里是因为对于控制UART0的寄存器组的地址是有规律的,也就是说每个寄存器占有四个字节,上一个寄存器的地址+4就是下一个寄存器的首地址,而ULCON0(0x50000000)就UART0寄存器组的第一个寄存器,可以理解为是该组寄存器的首地址。


查看数据手册,对于UART0来说,看一下其寄存器分配:


ULCON0  0x50000000 R/W  UART channel 0 line controlregister


 


UCON0  0x50000004 R/W  UART channel 0 controlregister


 


UFCON0  0x50000008 R/W  UART channel 0 FIFO controlregister


 


UMCON0  0x5000000C R/W  UART channel 0 Modem controlregister


 


UTRSTAT0  0x50000010 R  UART channel 0 Tx/Rx statusregister


 


UERSTAT0  0x50000014 R  UART channel 0 Rx error statusregister


 


UFSTAT0  0x50000018 R  UART channel 0 FIFO statusregister


 


UMSTAT0  0x5000001C R  UART channel 0 modem statusregister


 


UTXH00x50000020(L)


0x50000023(B)            W (by byte)     UART channel 0 transmit buffer register


 


URXH00x50000024(L)


0x50000027(B)             R (bybyte)     UART channel 0 receive bufferregister


 


UBRDIV0  0x50000028 R/W  Baud rate divisior register 0


 


 


接下来看第二个资源:


[1] =DEFINE_RES_NAMED(IRQ_S3CUART_RX0,


                    IRQ_S3CUART_ERR0 -IRQ_S3CUART_RX0 + 1,


                    NULL, IORESOURCE_IRQ)


首先把宏替换掉就是:


.start = IRQ_S3CUART_RX0,                             //74


             .end = RQ_S3CUART_ERR0 -IRQ_S3CUART_RX0 + 1,            //76-74+1       


             .name = NULL,                                


             .flags = IORESOURCE_IRQ,


对于IRQ就比较简单了,内核为每个中断都有对其唯一的IRQ号,这些号码定义在Irqs.h(archarmmach-s3c24xxincludemach)       文件中(对于中断号的问题,这些东西在裸机接扫寄存器的时候已经写的很详细了,通过中断号可以判定是哪个中断源引起的中断),可以看到:


UART0接收中断     #define IRQ_S3CUART_RX0        74


UART0发送中断     #define IRQ_S3CUART_TX0        75


UART0错误中断     #define IRQ_S3CUART_ERR0       76


在平台设备中定义的这些资源,可以通过在驱动程序通过函数:


platform_get_resource来或许相应的资源。


 


对于平台设备,暂时分析到这里,后面看驱动分析和测试部分。


 


2、对UART驱动的测试


假如够细心的话,可以在内核启动的时候看到:


s3c2440-uart.0:ttySAC0 at MMIO 0x50000000 (irq = 74, base_baud = 0) is a S3C2440

[1] [2] [3] [4] [5] [6] [7]
关键字:linux  UART  串口驱动 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic562891.html

上一篇:七 linux LCD驱动代码分析
下一篇:linux USB 摄像头 驱动 移植,使用

推荐阅读

OK6410A 开发板 (八) 113 linux-5.11 OK6410A rootfs 文件系统
struct file_system_type rootfs_fs_type = { .name = "rootfs", .init_fs_context = rootfs_init_fs_context, .kill_sb = kill_litter_super, };start_kernel vfs_caches_init mnt_init shmem_init init_rootfs 根据各个全局变量初始化 is_tmpfs
发表于 2022-08-10
OK6410A 开发板 (八) 114 linux-5.11 OK6410A各个文件系统的挂载
在 linux 启动过程中,挂载顺序如下 1. 内核 1. tmpfs // tmpfs 挂载到了 自己 ,有一个 根: dentry 和 inode , 对应一个 struct mount 2. rootfs // rootfs 挂载到了自己 ,有一个 根: dentry 和 inode , 对应一个 struct mount 3. bdev_cache_init 4. nsfs_init // 虽然挂载了,但是没注册文件系统 // cat /proc/filesystems 中找不到它对应的文件系统 5. devtmpfs // devtmpfs 挂载到了自己 ,有一个 根: dentry 和 inode , 对应一个 stru
发表于 2022-08-10
OK6410A 开发板 (八) 114 <font color='red'>linux</font>-5.11 OK6410A各个文件系统的挂载
OK6410A 开发板 (八) 115 linux-5.11 OK6410A 内存文件系统的挂载实例
mount -t tmpfs tmpfs /work/mount/struct mount 结构体$1 = (struct mount *) 0x816f5780 // struct mount 结构体 地址$2 = { // struct mount 结构体 内容 mnt_hash = { next = 0x0, pprev = 0x0 }, mnt_parent = 0x816f5780, // 表示挂载到了 /work/mount/ 所在的 struct mount 上 , 0x816f5780 为 /work/mount/ 所在的 struct mount 的地址 mnt_mountpoint = 0x8
发表于 2022-08-10
OK6410A 开发板 (八) 116 linux-5.11 OK6410A 用户空间虚拟内存布局
不同架构的 用户空间虚拟内存布局 不同, 以 arm 为例用户空间实际从0x10 000开始,从低到高有代码段,数据段,堆,栈用户空间范围为1000 -beff ffffvdsostacksigpageheap-mmap-ldlibcheap-brk数据段代码段vdso为了提供系统调用 ,x86提供了3类指令int/sysenter/syscall其中 sysenter和syscall相对于int来说,快一点而不管怎么快,都要从用户态切换到内核态新机制出现了,vsyscallvsyscall主要是 1.对特定的系统调用使用函数调用代替,即对一些系统调用进行加速 2.vsyscall还对系统调用进行入口管理,分发给int/sysent
发表于 2022-08-10
OK6410A 开发板 (八) 117 linux-5.11 OK6410A linux系统调用
访问内核空间,linux提供了系统调用,分为多类, 1.文件系统相关的接口open,read,等file_operations中的接口(具体有什么,看具体文件系统) 2.进程控制 3.进程通信 4.内存管理 5.系统控制 reboot 6.用户管理如何查看当前运行或者编译的 linux系统中有多少个 系统调用,以及分别是什么 编译时 : cat System.mmap |grep " sys_" , 这里面不仅包括系统调用,还有一些其他的东西,例如 sys_mmap_pgoff // 注意:sys_mmap_pgoff 不是 系统调用 编译时 : arch/arm/kernel/entry-common.S 中的
发表于 2022-08-10
OK6410A 开发板 (八) 116 linux-5.11 OK6410A 匿名inode
anon_inode_getfd & anon_inode_getfilecreates a new file instance by hooking it up to an anonymous inode,and a dentry that describe the "class" of the file通过将 "新文件实例"(file结构体) 连接到 "匿名inode" 和 "描述文件“类”的dentry" 来 创建新文件实例Creates a new file by hooking it on a single inode.This is usef
发表于 2022-08-10

推荐帖子

wince5.0添加触摸屏问题
我有一个2410的板子,运行5.0的操作系统.添加了触摸屏,但触摸屏什么反应都没有.运行touchcalibrate.exe时,程序一闪而过,无法打开,请问是什么问题?wince5.0添加触摸屏问题
hezhengli WindowsCE
pe导出函数问题
大家好: 根据导出函数表找到了addressofrunction的数组地址,并且根据addressofnameordinal和addressofname找到了相应的索引,但是有句代码我看不太懂,就是: WORDnumber=*((WORD*)(functionAddress+1)); if(number>ped->NumberOfNames)continue; lstrcpy
hilin029 嵌入式系统
电子时钟设计, 使用定时器设计具有时、分、秒显示的电子时钟,1602显示屏显示msp430
这个其实是MSP430的单片机的题,因为没有这个模块要求:使用定时器设计一个具有时、分、秒显示的电子时钟(采用1602液晶显示),并定义一个启动键,当按下该键时电子时钟从当前值开始走时,再按一下停止走时。1》我的思路是用定时器A先采用增计数模式,然后当摁下启动键后,对自己定义的时间进行增计数,再摁下后,产生中断信号,停止计数,之后恢复到之前停止计数的状态进行重新计数。我不知道这样的方法可行吗??2》我看到还有个RTC模块,但这个我不知道怎么用求解如果可以的话,可以写上定时器的具
lulla 51单片机
电子设计大赛中怎样领导团队前进?
本帖最后由paulhyde于2014-9-1509:36编辑我们都在不断寻找关于电子设计大赛的种种资料,忙的不亦乐乎!但是要想赢得比赛,我们却不知不觉把一个很重要的因素淡忘了,那就是团队的力量!!!那么我们该怎么建立一个优秀的团队,和采取怎样的团队管理办法呢?忘各个团队的负责人,和有经验的盟友研讨! 电子设计大赛中怎样领导团队前进?
小平无间道 电子竞赛
只为uC而生,uS成长历程 9
昨晚我们已经基本阐明了这样一个以(字节间)超时作为判断一串数据是否接收完整的超时机制的完整思路和假设性分析。 为了避免过于冲突,今晚我仍然不会立马切到我之前上传的那份我经过整理的已经变成一个足以成为第三方库的模块。 而是以串口为例,从一个更加符合逻辑的过程来进行这个模块功能的一步步实现的推演过程。只为uC而生,uS成长历程9
辛昕 编程基础
LP54100 而非LPC1100系列接收心得-{澄清下}
本帖最后由fyaocn于2015-3-1811:24编辑 本次按照LPC54100准备,不过收到的时候是LPC1100,没有准备,所以不大熟悉。所以这次就先比较一下。 LPC54100是高性能MCU,属于典型的低功耗,高性能芯片。主要的均衡的性能和随时唤醒的低功耗功能,很适合现在热门的物联网设计和有关的设备。内核是双核的32位ARMCortex-M4F/M0+100MHz,最多到512kB板载Flash,低功耗的串行接口I2C,UART,SPI,最多50个GPI
fyaocn NXP MCU
小广播
实战 培训 开发板 精华推荐

何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2022 EEWORLD.com.cn, Inc. All rights reserved