Windows CE串口驱动简析(2)-PDD层实现:CReg2410Uart和TX部分(基于WinCE5.0 SMDK2410 BSP的Serial驱动)

二.PDD层
1.PDD架构
现在我们就来看看SMDK2410中串口驱动的PDD部分.
MDD层和PDD COMMON层都是由微软提供的,一般情况下我们基本无须改动.微软为开发者提供了一个CSerialPDD类作为开发工作的起点.CSerialPDD是个纯虚类,我们需要将驱动程序的PDD层定义成CSerialPDD类的继承类,其成员必须准确全面的反应目标硬件平台的特定类型串口的属性.
MDD和PDD COMMON层不需要知道用户的CSerialPDD继承类的命名和具体实现,以CSerialPDD类指针引用其继承类实例的功能.
CSerialPDD的定义如下(位于/WINCE500/PUBLIC/COMMON/OAK/INC/cserpdd.h):

CSerialPDD类以CRegistryEdit类作为它的父类.CRegistryEdit向它的继承类提供了访问系统注册表的能力.成员函数定义在cserpdd.cpp中.
CSerailPDD类的数据成员和成员函数可以划分为以下几个部分:
(1) 初始化部分
(2) 串口设备操作部分
(3) 电源管理部分
(4) 中断接口部分
(5) 数据发送与接收部分
(6) MODEM功能部分
(7) 线路功能部分
(8) 串口配置部分
(9) IR特殊处理部分
(10) 错误处理部分
SMDK2410串口驱动PDD中CSerialPDD的继承类就是CPdd2410Uart,这是2410平台上3个UART端口都拥有的共同一个抽象类,里面实现了串口大部分操作与具体哪个UART无关.
而CPdd2410Uart的继承类CPdd2410Serial1和CPdd2410Serial2则实际对应于具体串口,分别为UART0和UART1.
CPdd2410Uart实现在pdds3c2410_ser.cpp,而CPdd2410Serial1和CPdd2410Serial2实现在ser_smdk2410.cpp.
下面就先来看看CPdd2410Uart类.
2.CPdd2410Uart
(1)CPdd2410Uart原型
该类原型如下,继承自CSerialPDD和CMiniThread类.

(2)CReg2410Uart
在详细看CPdd2410Uart的成员函数之前,我们先来看看CPdd2410Uart会用到的另一个类CReg2410Uart.这个类封装了对串口寄存器的操作函数.原型如下:
  
其中Write_ULCON,Read_ULCON等就是读写相应的UART寄存器,后面的m_pReg就是操作寄存器的虚拟地址.使用的READ_REGISTER_ULONG和WRITE_REGISTER_ULONG是CEDDK函数,用来读写寄存器.
下面来看看其他几个成员函数.
[1] 构造函数CReg2410Uart
  
这个函数只是用来获得CPU时钟,同时给m_pReg附初值,也就是对应的UART寄存器地址.
[2] Init
用来初始化UART寄存器初值,都设为0.
   
[3] Backup,Restore
用来备份和回复UART寄存器内容.

[4] Write_BaudRate
写波特率,首先判断UCON(UART控制寄存器)BIT10选择分频时钟源,然后写UBRDIV(波特率分频寄存器)来设置波特率.
   
另外还有个DumpRegister,用来输出寄存器值,供调试使用,这里就不多说了.
下面就来看看CPdd2410Uart的成员函数.
3.CPdd2410Uart构造函数
初始化了一些变量,如CReg2410Uart类对象,事件及其他标志等.注释如下:
 
4.析构函数~CPdd2410Uart()
主要就是关闭线程,关闭事件,禁止中断,释放地址空间资源,如CReg2410Uart类对象空间,寄存器地址空间等.
  
5.Init
该函数首先调用基类的Init函数,CSerialPDD的Init成员函数主要负责初始化串口驱动程序的电源管理.Init同时并检查注册表是否打开和m_XmitFlushDone,都为TRUE则进一步初始化.
然后通过GetIsrInfo获得逻辑中断号,创建IST事件(m_hISTEvent),初始化m_dwSysIntr对应的中断.触发事件为m_hISTEvent.
接着读注册表获取如DeviceArrayIndex,InterruptBitsShift,ISTTimeouts等信息.
最后调用MapHardware和CreateHardwareAccess来映射硬件寄存器和创建特定UART的CReg2410Uart类对象.

接下来就来看看MapHardware和CreateHardwareAccess这两个函数.
[1] MapHardware
该函数首先判断m_pRegVirtualAddr是否为NULL,如果为NULL说明未初始化,第一次运行时应该为NULL,接着使用DDKWINDOWINFO的结构通过读注册表还获得InterfaceType和MemBase,MemLen(注册表中设置的是50000000,即UART0寄存器物理地址)然后调用TranslateBusAddr将一个总线相对地址转换成系统物理地址.使用MmMapIoSpace映射到IO虚拟地址空间.最后将2410中断寄存器物理地址映射到IO虚拟地址空间.之所以有这样的转换过程,是因为2410串口的母总线是Busenum.

[2] CreateHardwareAccess
这个函数就是生成CReg2410Uart类对象,针对具体的串口(注册表中设置的是UART0),这样调用该对象的成员函数就是对UART0寄存器进行读写操作了.
  
6.PostInit
该函数也是初始化函数,在Init之后调用,首先设置一个CRITICAL_SECTION防止重入写冲突,然后设置UCON为0,禁止UART中断.如果此时SUBSRCPND有中断请求,则调用InitReceive和InitLine进行接收并使能中断结束后清除中断标志位.InitReceive和InitLine留在后面的内容分析.当确定SUBSRCPND无中断请求时,调用基类的PostInit和设置线程优先级(从注册表项Priority获得),并启动线程.
CSerialPDD::PostInit功能是初始化中断处理和初始化MODEM.

7.ThreadRun
这个就是IST线程,创建自CMiniThread类,CMiniThread类封装了对线程的基本操作,如ThreadStart,ThreadStop等.详情可参考/WINCE500/PUBLIC/COMMON/OAK/INC/Cmthread.h.
像通常的驱动IST一样,首先等待事件m_hISTEvent的发生,发生后去获取中断状态来判断是哪个中断发生了,根据不同的状态设置不同的标志.然后调用NotifyPDDInterrupt(基类CSerailPDD函数实现)向串口驱动程序报告串口中断事件,接着清除中断标志位.最后调用InterruptDone结束本次中断IST过程.
当其他中断(RX,TX)没有发生时,IST会默认INTR_MODEM来轮询MODEM.也就是最后else里做的工作.代码如下:
  
8. InitialEnableInterrupt
这个函数比较简单,用来初始化允许或者禁止RXD和ERR中断.

9.InitXmit
InitXmit负责初始化串口的数据发送,该函数有一个bool型参数bEnable,TRUE表示初始化数据发送,FALSE表示解除初始化串口数据发送.
如果为TRUE,则初始化UART寄存器,设置中断方式(level触发,传输模式-中断请求或轮询),复位发送FIFO,禁止FIFO,Tx FIFO中断触发方式(4字节),最后重新使能FIFO.
如果为FALSE,则等待UTRSTA寄存器FIFO状态为空,即数据都已发送完毕.
代码如下:
  
10.GetWriteableSize
GetWriteableSize用来获取FIFO中可以写入的字节数.首先读取UFSTAT来获得当前FIFO状态,如果为FULL则返回0,无可写字节数.如果不为0,则计算出当前可写字节数,并返回.
代码如下:

11. XmitInterruptHandler
XmitInterruptHandler被串口驱动程序的IST线程调用用以处理串口的数据发送.

中断发生后,调用的过程是这样的:中断发生后,m_hISTEvent事件触发,IST线程ThreadRun获取中断类型调用NotifyPDDInterrupt(cserpdd.c)通知PDD,NotifyPDDInterrupt会调用MDD层中的SerialEventHandler(mdd.c),该函数会根据不同的状态调用相应的事件处理程序,如发送数据处理XmitInterruptHandler.
XmitInterruptHandler首先判断是否有发送数据,如果没有直接关闭中断返回.如果有则判断是否需要流控制,没有流控制仅仅关闭中断;如果需要流控制,则FIFO可写字节数,将该数目的字节写入UTXH(发送Buffer寄存器)中,写满后打开中断返回.最后清除中断标志位.

12. XmitComChar
XmitComChar供驱动程序发送单个字符,主要是软件流控制情况下的X-ON和X-OFF流控字符,以及应用程序以IOCTL_SERIAL_IMMEDIATE_CHAR为操作码调用COM_IOControl函数向串口发送立即字符.
如果FIFO not full,则向UTXH发送字符数据,否则允许发送中断,等FIFO中数据发送完毕后在发送(等待m_XmitFlushDone事件).

13. EnableXmitInterrupt
EnableXmitInterrupt是暂时地关闭及重新开启串口的发送中断.

14. CancelXmit
CancelXmit取消串口的数据发送,直接调用InitXmit(TRUE)重新初始化,如reset fifo等.    

下一篇接着来看接收RX及MODEM,LINE,IR部分.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章