广州周立功单片机发展有限公司 Tel,(020)38730976 38730977 Fax,38730925 http://www.zlgmcu.com
1
PDIUSBD12 DMA模式应用指南
1,基于协议的DMA操作简介
PDIUSBD12有6个端点其中2个控制端点2个普通端点和2个主端点主端点支持DMA传输
在基于协议的DMA操作中主机应用程序询问器件的固件以通过由控制端点发送的厂商请求建立
DMA传输然后在主端点上执行实际的批量数据传输在DMA控制器建立之后主机可向器件传输最多为
64k字节的数据而不需要任何固件的干预
一个完整的DMA传输要求以下两个步骤
1) 通过主管道发送一个请求并允许器件用DMA传输方向起始地址和传输规格对DMAC进行编程
2) 在主端点上发送或接收数据包
2,器件DMA状态
建立DMA请求通过控制管道作为厂商请求从主机发出器件的响应和动作依赖于DMA操作的状态
上图所示为器件中DMA的3种状态IDLE RUNNING和PENDING如果没有运行或推迟DMA
操作器件处于IDLE状态那么建立DMA请求由ACK进行响应如果器件在DMA传输的过程中就是
RUNNING状态建立DMA请求由NAK进行响应并导致器件进入PENDING状态这表示有一个推迟的建立DMA请求如果器件在PENDING状态中接收到另一个建立DMA请求新的请求将覆盖旧的请求
IDLE
PENDING
RUNNING
IOCTL,Setup DMA / ACK EOT
IOCTL,Setup DMA / NAK
EOT / ACK
IOCTL,Setup DMA / NAK
Overwrite previous setup DMA request
广州周立功单片机发展有限公司 Tel,(020)38730976 38730977 Fax,38730925 http://www.zlgmcu.com
2
下图为固件处理建立DMA请求和EOT的程序流程图
DMA配置寄存器
D12的DMA操作由其DMA配置寄存器进行控制该寄存器由设置DMA命令设置寄存器中不是所有的位都和DMA操作有关位4中断脚模式和位7时钟分频系数控制D12的中断源
下表所示为推荐的寄存器编程汇总
位 名称 DMA模式 非DMA模式
0&1 DMA字符串 `1`&`1` 无关
2 DMA使能 `1` `0`
3 DMA方向 `1`用于IN标志
`0`用于OUT标志
无关
4 自动重装 `0` 无关
5 中断脚模式 `0` `0`
6 端点4中断使能 `0` `1
7 端点5中断使能 `0` `1`
默认情况下D12和DMAC都不处于自动重装模式不想让器件的DMA自动重新启动是因为这是一个协议层的操作也就是说在主机的控制之下在EOT D12和DMA控制器的DMA都被禁止固件需要重新使能以使它们在接收到主机的建立DMA请求时重新启动DMA传输
需要注意的是在DMA模式中来自端点4和5的中断被禁止这些端点上的中断服务是不必要的而且使DMA传输中有潜在的缺陷DMA可以看作是最高级的中断可以在任意两条CPU指令之间执行甚至在ISR中由于在传输当中DMA的状态任何时候都有可能改变因此任何想要用来检测DMA状态的程序都是不可靠的
以下是一个IN 标志DMA传输编程示例,dma_dir和dma_transfer_size已通过建立DMA请求设置
dma_start(dma_dir,MainDmaBuf,dma_transfer_size,3);
dma.bits.dma_burst = 3;
dma.bits.dma_enable = 1;
dma.bits.dma_direction = dma_dir;
dma.bits.auto_reload = 0;
dma.bits.normal_plus_sof = 0;
dma.bits.endp_4_interrupt_enable = 0;
Write Register
Setup DMA
Request?
State = IDLE?
Save Setup DMA Request
Program DMAC
Program D12's DMA Configuration Register
State <- RUNNING
ACK Device Request
State <- PENDING
End of Write Register
Stall Control Endpoint
Yes
No
Yes
No
EOT
State = PENDING?
Program DMAC
Program D12's DMA Configuration Register
State <- RUNNING
ACK Device Request
State <- IDLE
End of EOT
Yes
No
广州周立功单片机发展有限公司 Tel,(020)38730976 38730977 Fax,38730925 http://www.zlgmcu.com
3
dma.bits.endp_5_interrupt_enable = 0;
D12_SetDMA(dma);
建立DMA请求
建立DMA请求是一个通过控制管道发送的厂商请求在PDIUSBD12采样固件和小应用程序中这些是由IOCTL_WRITE_REGISTER由微软Windows 98 DDK中的静态图像USB接口定义完成的器件请求描述如下
偏移 字段 规格 值 备注
0 BmRequestType 1 0x40 厂商请求器件到主机
1 Brequest 1 0x0C IOCTL_WRITE_REGISTERd固定值
2 Wvalue 2 0 偏移设置为零
4 Windex 2 0x0471 建立DMA请求的固定值
6 Wlength 2 6 建立DMA请求的数据长度
在器件请求之后DMA操作的具体请求在数据阶段发送采样固件和小应用程序使用专有的定义如下所示
偏移 字段 备注
0 地址7 0
1 地址15 8
2 地址23 16
已请求DMA传输的地址
3 类型7 0
4 类型15 8
传输的规格
5 命令 位7 `1`启动DMA传输
位0 `1`IN标志`0`OUT标志
主机端编程注意事项
USB器件不是决定传输速率的唯一标准主机端的应用程序在整个系统的性能占有更重要的地位因为主机一直在控制USB的处理
DMA传输是一个包括了控制端点和主端点的连续操作由于下一步操作由前一操作的结果决定所以协作非常重要虽然多线程可用于对不同管道进行访问以增加系统的性能但使用单线程却使处理建立
DMA请求IOCTL和数据传输写文件/读文件操作的编程容易许多
IOCTL_WRITE_REGISTER和IOCTL_READ_REGISTER使用结构IO_BLOCK与器件驱动器进行数据交换下面所示的结构定义是微软静态图像USB接口的一部分
typedef struct _IO_BLOCK {
IN unsigned uOffset;
IN unsigned uLength;
IN OUT PUCHAR pbyData;
IN unsigned uIndex;
} IO_BLOCK,*PIO_BLOCK;
IO_REQUEST 结构是一个专有的定义包含了建立DMA请求的细节
typedef struct _IO_REQUEST {
unsigned short uAddressL;
unsigned char bAddressH;
unsigned short uSize;
unsigned char bCommand;
} IO_REQUEST,*PIO_REQUEST;
举例程序如下
ioRequest.uAddressL = 0;
广州周立功单片机发展有限公司 Tel,(020)38730976 38730977 Fax,38730925 http://www.zlgmcu.com
4
ioRequest.bAddressH = 0;
ioRequest.uSize = transfer_size;
ioRequest.bCommand = 0x80; //start,write
ioBlock.uOffset = 0;
ioBlock.uLength = sizeof(IO_REQUEST);
ioBlock.pbyData = (PUCHAR)&ioRequest;
ioBlock.uIndex = 0x471;
bResult = DeviceIoControl(hDevice,
IOCTL_WRITE_REGISTERS,
(PVOID)&ioBlock,
sizeof(IO_BLOCK),
NULL,
0,
&nBytes,
NULL);
if (bResult != TRUE) {
testDlg->MessageBox("Setup DMA request failed!","Test Error");
return;
}
bResult = WriteFile(hFile,
pcIoBuffer,
transfer_size,
&nBytes,
NULL);