前言
驱动的编写无非就是寄存器的配置,所以我们先要对控制器的寄存器现有一个整体的概览,知道有哪些寄存器,配置某个功能要操作哪些寄存器,寄存器的整体组织架构,等等。现有了整体了解后面具体莫格模块和功能的配置式就可以找到地方,然后参考具体的寄存器的描述进行配置。
概览
前面DWC_otg_core架构部分,已经介绍了控制和状态寄存器CSR的一些内容。从架构的角度看CSR块位于AHB时钟域,但是有两个特殊的,一个是电源和时钟门控寄存器PCGCCTL和控制器中断寄存器GINTSTS的b[31:29],这些寄存器位位于BIU从模块中,在断电模式下依然处于活动状态。为什么这两个不一样呢? 因为要进行低功耗管理,要对AHB和PHY以及RAM的时钟进行门控即可关闭和打开,如果位于AHB时钟域那么关闭AHB时钟域时这个寄存器本身也就断电了,也就没办法退出断电模式了,所以这个寄存器必须位于AHB时钟域以外。GINTSTS的b[31:29] WkUpInt SessReqInt DisConnInt也是类似的原因。
站在USB控制器的角度,对应的是AHB从接口,即外部CPU通过AHB主和控制器的AHB从通讯,读写控制器的CSR寄存器,注意控制器本身也是要写CSR的状态和中断相关的寄存器的,因为要设置中断标志各种状态等,同时也要读CSR因为要根据寄存器中的配置决定自己的行为。那么就存在CPU和控制器都同时去写某些寄存器的可能,主要是中断相关的,比如控制器要置位某个中断位,而软件要去清除某个中断位,此时控制器的写是优先的,即控制在写时软件的写会忽略掉,这么做的原因是避免丢失中断事件。
另外注意所有寄存器都是32位访问的,哪怕寄存器本身只需要一个字节。由于中断位的设置和清零分别是控制器和软件通过AHB接口去访问的,可能同时写,所以硬件上做了处理,不同中断位的写是完全独立的,控制器和AHB接口可以同时写不同的中断位,这是硬件保证的,而不是我们通常的读-修改-写的实现方式就是出于该考虑。如果是写同样的中断位呢,那就是上面说的控制器优先忽略AHB的写。
为了节省空间,HSOT和DEVICE模式的寄存器是共用物理空间的,因为同一时间要不是主机模式要不是设备模式。另外有些寄存器要根据配置决定是否实现,比如如果只有两个端点,那么其他端点相关寄存器就没有实现,但是空间还是占用的,这样是为了方便代码兼容,也就是寄存器的偏移地址都是固定的,没有实现的的就空着。未实现的寄存器写忽略读返回值不确定。这里注意只有全局控制, 电源和时钟门控, Data FIFO 访问,和 Host Port 寄存器是主机和设备都可以访问的,其他是模式相关的寄存器。如果主机模式去写设备相关的寄存器(反之亦然)则会产生GINTSTS.ModeMis事件,该为置位,如果使能了对应中断还会产生中断,写会忽略读返回值不确定。
如果切换了模式则需要重新编程所有相关寄存器,就好比上电复位之后的状态一样。
CSR存储映射
CSR的地址映射是固定的,不随着配置改变而改变,即每一个寄存器的偏移是固定的,前面已经解释过了原因。主机和设备模式寄存器占用不同的地址。
整个寄存器的空间如下所示
阅读寄存器有一些经验,
G开头的代表全局控制寄存器
H开头的代表主机相关寄存器
D开头的代表设备相关寄存器
这样一眼就可以看到寄存器大概是和什么相关的。
Controller Global CSRs (1 KB)部分:主机和设备模式都可以访问
Host Mode CSRs (1 KB):进入主机模式需要配置的寄存器
Device Mode CSRs (1.5 KB):进入设备模式需要配置的寄存器
Power and Clock Gating CSRs (0.5 KB):实际只有一个寄存器,电源和门控配置,主机和设备模式都可以访问。
Device EP x/Host Channel x FIFO (4 KB):这些寄存器在主机和设备模式下都可用,用于在给定方向上读取或写入特定端点或通道的FIFO空间。在主机通道IN端点则FIFO只读,OUT端点则FIFO只写,在设备IN端点则FIFO只写,OUT端点则FIFO只读,注意这里的IN和OUT是符合USB规范的IN和OUT即都是针对主机而言的。
Direct Access to Data FIFO RAM for Debugging (128 KB):直接访问该空间可以查看RAM中数据用于调试使用。
中断相关寄存器架构
中断相关寄存器非常重要,可以说USB的驱动就是基于中断的驱动,所有流都是中断去驱动的,当然也有所谓的基于事件的驱动比如uC-USB实际也是在中断服务函数中发送信号量或者事件,在某个线程中或者主循环中去处理事件,本质还是一样的,还是基于中断的。中断中根据状态决定下一步要做什么。
对应中断状态寄存器GINTSTS,中断是一个分层的结构,即总分的形式,先整体有总的中断状态,比如是设备IN还是OUT端点中断,是主机Port还是通道相关中断,是OTG的中断,还是内核相关的中断。比如如果知道是设别IN或者OUT中断则往下走一层看是DAINT是哪一个IN端点或者哪一个OUT端点的中断,找到了然后再往下走一层查看具体的DIEPINTi或者DOEPINTi已确认更详细的中断信息。
还有就是编程上需要注意使能中断时一定要先清除中断标志再使能中断,避免一使能中断标志就是置位的马上就产生中断,这也是驱动开发的常识。
中断架构还支持多处理器模式,即可以将中断信号分发到不同的处理器,以配合多处理器系统使用。支持多处理器中断模式时就是多了包含EACH字样的寄存器,供各自处理器使用对应的中断寄存器。
中断的处理如下,即和上面提到的层次结构对应
1.先看GINGSTS总中断状态,处理全局的中断
2.然后看主机或者设备通道或者端点相关中断状态 比如看DAINT
3.最后看具体是哪一个端点或者通道比如看DIEPINTi,DOEPINTi。
主要使用的寄存器
这里先对一些高频使用的寄存器做简单介绍,介绍其对应的功能,详细的可以再参考具体的寄存器描述。这样先从整体有一个了解。
GOTGCTL全局OTG控制和状态寄存器:控制OTG行为并反映控制器的OTG功能的状态。 | ||
11 | DevHNPEn 设备设置主机协商协议使能 这是设备端的操作 | 设备端收到主机的SetFeature.SetHNPEnable命令时设置该位。 0HNP不使能 1HNP使能 |
10 | HstSetHNPEn 主机设置主机协商协议使能 这是主机端的操作 | 主机端在SetFeature.SetHNPEnable命令完成后设置该位 0主机设置HNP不使能 1主机设置HNP使能 |
GAHBCFG:全局AHB控制寄存器,上电或者切换模式时配置AHB相关信息,只能传输前初始化一次 | ||
5 | DMAEn 使能DMA | 只有IP配置支持DMA才可以选,如果是OTG_ARCHITECTURE = 0则固定为Slave-Only模式没得选。 0 使用Slave模式 1 使用DMA模式 |
GUSBCFG:全局USB配置寄存器,上电或者切换模式时配置AHB相关信息,只能传输前初始化一次,USB和PHY相关配置 | ||
30 | ForceDevMode 强制为设备模式 | 写1强制为设备模式,而不管utmiotg_iddig信号。设置后需要等25mS生效。只有OTG_MODE = 0, 1 , 2时才有效。 |
29 | ForceHstMode 强制为主机模式 | 写1强制为主机模式,而不管utmiotg_iddig信号。设置后需要等25mS生效。只有OTG_MODE = 0, 1 , 2时才有效。 |
9 | HNPCap HNP功能使能 | 控制使能HNP功能,写1使能。注意这里和上面的DevHNPEn和HstSetHNPEn不一样,这里是有HNP的功能是否使用,只有使用了才支持HNP,才有上面的SetFeature.SetHNPEnable协商之后的结果设置。 只有OTG_MODE中支持HNP的模式才有效。 |
8 | SRPCap SRP功能使能 | 写1使能,即对于B设备请求连接的A设备激活VBUS和启动session。 只有OTG_MODE中支持SRP的模式才有效。 |
6 | PHYSel PHY选择 | 0: USB 2.0 高速 UTMI+ 或ULPI PHY,只有OTG_HSPHY_INTERFACE = 1支持高速PHY接口才能设置为0 1: USB 1.1 全速串行收发器,只有OTG_FSPHY_INTERFACE = 1支持全速接口才能设置为1 |
4 | ULPI_UTMI_Sel PHY接口ULPI和UTMI选择 | 0选择UTMI+ 1选择ULPI 只有OTG_HSPHY_INTERFACE = 3时同时支持UTMI+和ULPI时才有的选,否则IP配置为什么就是什么。 |
3 | PHYIf 选择接口宽度 | 只对选择了UTMI+的才可配置 对于ULPI只能配置为0即8位。 0 :8位 1:16位 |
HCFG:主机配置寄存器,只初始化时配置一次 | ||
23 | DescDMA 是否使能基于描述符的DMA | 只有IP配置支持 Scatter/Gather DMA 才能使能。 有一下几种组合 GAHBCFG.DMAEn=0, HCFG.DescDMA=0 => Slave mode
GAHBCFG.DMAEn=0, HCFG.DescDMA=1 => Invalid
GAHBCFG.DMAEn=1, HCFG.DescDMA=0 => Buffered DMA mode
GAHBCFG.DMAEn=1, HCFG.DescDMA=1=> Scatter/Gather DMA mode |
2 | FSLSSupp | 在主机模式设置该位为1则不管设备支持什么速度都枚举为全速或者低速,而如果设置为0则根据实际设备支持什么速度就枚举成什么速度。 |
HCCHARn:主机通道相关特性设置 | ||
19:18 | EPType | 设置通道类型 00: Control 01: Isochronous 10: Bulk 11: Interrupt |
15 | EPDir | 端点方向 0:OUT 1:IN |
14:11 | EPNum | 端点号
|
10:0 | MPS | 对应端点最大包大小 |
HCTSIZn:主机通道传输大小配置 | ||
30:29 | PID | 应用设置数据的初始类型,后续的控制器硬件自动更新(所以这里明确了哪些是软件做哪些是硬件做,之前就提到过写驱动理解这一点很重要,这些信息都是从手册中获取) 00: DATA0 01: DATA2 10: DATA1 11: MDATA (non-control) |
DCFG:设备配置寄存器,枚举或者控制为设备模式时配置,只初始化配置一次 | ||
25:24 | PerSchIntvl | 周期调度间隔 只有Scatter/Gather DMA模式才有 配置一个微帧内DMA花多少时间去处理同步IN数据,剩余的时间处理非同步传输。对于UVC 同步传输等可以提高该值以达到高传输速率。 如果没有同步端点则该配置被忽略。 00: 25% of (micro)frame. 01: 50% of (micro)frame. 10: 75% of (micro)frame. 11: Reserved |
23 | DescDMA | 只有IP配置支持 Scatter/Gather DMA 才能使能。
支持的组合如下 GAHBCFG.DMAEn=0,DCFG.DescDMA=0 => Slave mode
GAHBCFG.DMAEn=0,DCFG.DescDMA=1 => Invalid
GAHBCFG.DMAEn=1,DCFG.DescDMA=0 => Buffered DMA mode
GAHBCFG.DMAEn=1,DCFG.DescDMA=1 => Scatter/Gather DMA mode |
10:4 | DevAddr | 收到主机的SetAddress命令后设置对应的地址值 |
1:0 | DevSpd | 软件设置该值要求硬件枚举为对应的速度。硬件速度枚举后反应最终实际的速度。 也就是软件可以要求,但是实际是多少硬件说了算,这也是前面提到的什么是软件做什么是硬件做的体现,编程要知道这些信息。 00:High speed (USB 2.0 PHY clock is 30 MHz or 60 MHz) 01: Full speed (USB 2.0 PHY clock is 30 MHz or 60 MHz) 10: Reserved 11: Full speed (USB 1.1 transceiver clock is 48 MHz) |
DIEPCTLn/DOEPCTLn:端点控制寄存器,控制对应端点的行为 | ||
29 | SetD1PID | Scatter/Gather DMA 和 nonScatter/Gather DMA 模式都可使用。 配置数据的类型为DATA1 只对中断/批量 IN和OUT端点有效。 |
28 | SetD0PID | Scatter/Gather DMA 和 nonScatter/Gather DMA 模式都可使用。 配置数据的类型为DATA0 只对中断/批量 IN和OUT端点有效。 |
19:18 | EPType | 端点类型 00: Control 01: Isochronous 10: Bulk 11: Interrupt |
10:0 | MPS | 对应端点的最大包大小 |
寄存器描述
阅读寄存器要注意下寄存器的属性
读写属性 | 描述 |
RC | 读清除 |
RS | 读置位 |
RM | 读会修改寄存器内容 |
Wo | 只能写一次 |
W1C | 写2清除 |
W1S | 写1置位 |
W1T | 写1翻转 |
W0C | 写0清除 |
W0S | 写0置位 |
W0T | 写0翻转 |
WC | 写清除. |
WS | 写置位 |
WM | 写反转 |
no Read Behavior attribute | 不能读Write-Only. |
no Write Behavior attribute | 不能写Read-Only |
访问属性 | 描述 |
R | 只读 |
W | 只写 |
R/W | 可读写 |
R/W1C | 可读,写清除 |
RC/W1C | R读清除,写1清除 |
R/Wo | 可读,只能写一次. |
属性 | 描述 |
Volatile | IP-XACT 规格定义的,写后读或者连续读不保证内容一致性。 |
Testable | IP-XACT 规格定义的,可能的值unconstrained, untestable, readOnly, writeAsRead, restore. |
Reset Mask | IP-XACT 规格定义的. 复位值不确定. 比如其复位值受其他寄存器或者硬件引脚影响或者基于RAM的寄存器. |
* Varies | 可变的,即根据实际的配置而变化 |
寄存器组织
寄存器按块组织
DWC_otg_map/DWC_otg_intreg
所有寄存器如下
可以看到就是分为G开头,H开头和D开头的。
总结
本文对控制器的寄存器有了一个整体上的概览,先了解个大概,了解寄存器的组织结构,大致了解一下常用的寄存器。后面编程时再一个个对照每一个寄存器的描述去编写代码。