阅读:23909回复:88
D12->C51驱动程序开发
建议由浅入深开展应用D12的USB C51驱动程序开发讨论。
在这个主题中,我想和网友共同探讨USB设备与主机的USB交互问题。 在《WDM驱动程序---USB驱动开发》中,我想和网友共同探讨USB设备驱动WDM开发问题。 在 《USB应用程序开发》中,我想和网友共同探讨USB应用程序开发问题。 [编辑 - 5/11/02 by plasma] |
|
沙发#
发布于:2002-03-16 22:41
你能不能先开一个头呢?
|
|
板凳#
发布于:2002-03-16 22:49
我觉得应该看系统的用途而定 找最相近的usb类进行编程 不知道对不对
|
|
|
地板#
发布于:2002-03-17 11:55
面对主机USB设备首先要处理的是主机标准控制请求。
下面代码可作为开发USB设备面对主机的模板。 [1] 处理主机标准控制请求: unsigned char ENDPOINT_A0_FIFO[8]; //判断输入的是SETUP请求,并将其读入缓冲区ENDPOINT_A0_FIFO ... if((ENDPOINT_A0_FIFO[0] & 0b01100000)==0x00) { if (ENDPOINT_A0_FIFO[1] <= 0x0C) { (*StandardFunctionTable[ENDPOINT_A0_FIFO[1]])(); return; } } ... const void (* StandardFunctionTable[])(void)= { GetStatus,ClearFeature,USB_Reserved,SetFeature, USB_Reserved,SetAddress,GetDescriptor,SetDescriptor, GetConfiguration,SetConfiguration,GetInterface, SetInterface,SynchFrame }; |
|
地下室#
发布于:2002-03-17 15:16
void GetStatus(void)
{ switch (ENDPOINT_A0_FIFO[0]) { case (0b10000000)://返回设备状态 //发送两个字节数据:第一字节D1 为1支持远程唤醒、为0不支持远程唤醒,D0 为1设备自己供电、为0 USB总线供电,其它位为0;第二字节为0。 break; case (0b100000001)://返回接口状态 //发送两个字节数据:第一字节为0;第二字节为0。 break; case (0b10000010)://返回端点状态 //发送两个字节数据:第一字节D0为1端点处于暂停,否则D0为0,其它位为0;第二字节为0。 break; } } [编辑 - 3/17/02 作者: plasma] |
|
5楼#
发布于:2002-03-17 16:27
void ClearFeature(void)
{ if ((ENDPOINT_A0_FIFO[0] ==0b00000000) && (ENDPOINT_A0_FIFO[2] == 1) && ( !ENDPOINT_A0_FIFO[3])) { //清除设备远程唤醒功能 return; } if ((ENDPOINT_A0_FIFO[0] ==0b00000001) && (ENDPOINT_A0_FIFO[2] == 0) && ( !ENDPOINT_A0_FIFO[3])) { //清除设备接口特殊功能 ENDPOINT_A0_FIFO[4] 为接口号 return; } if ((ENDPOINT_A0_FIFO[0] == 0b00000010) && (ENDPOINT_A0_FIFO[2] == 0) && (!ENDPOINT_A0_FIFO[3])) { //清除设备端点暂停功能 ENDPOINT_A0_FIFO[4] D7为端点方向,D3~D0为端点号 return; } } |
|
6楼#
发布于:2002-03-17 16:44
void USB_Reserved(void)
{ //只发确认信息。 } void SetFeature(void) { if ((ENDPOINT_A0_FIFO[0] ==0b00000000) && (ENDPOINT_A0_FIFO[2] == 1) && ( !ENDPOINT_A0_FIFO[3])) { //设置设备远程唤醒功能 return; } if ((ENDPOINT_A0_FIFO[0] ==0b00000001) && (ENDPOINT_A0_FIFO[2] == 0) && ( !ENDPOINT_A0_FIFO[3])) { //设置设备接口特殊功能 ENDPOINT_A0_FIFO[4] 为接口号 return; } if ((ENDPOINT_A0_FIFO[0] == 0b00000010) && (ENDPOINT_A0_FIFO[2] == 0) && (!ENDPOINT_A0_FIFO[3])) { //设置设备端点暂停 ENDPOINT_A0_FIFO[4] D7为端点方向,D3~D0为端点号 return; } } |
|
7楼#
发布于:2002-03-17 17:05
void SetAddress(void)
{ if (ENDPOINT_A0_FIFO[0] == 0b00000000) { //保存USB地址 0x80 | ENDPOINT_A0_FIFO[2]; } } /* 注: SetAddress请求实际可分成三个阶段。第一阶段,Setup包被送至设备,第二个可有无的阶段,数据在设备与主机之间传送,第三阶段,状态信息在主机与设备之间传送。 数据与状态传送的方向要看是主机发数据给设备还是设备发数据给主机。状态的传送方向总是与数据传送方向是相反的,如果没有数据传输阶段则状态由设备传向主机的。 Setup包传送以后的两个阶段的地址保持与Setup包传送阶段一致。USB设备只有在Status阶段过后才能改变设备地址。 */ |
|
8楼#
发布于:2002-03-17 22:29
void GetDescriptor(void)
{ if ( (ENDPOINT_A0_FIFO[0] != 0b10000000 DEVICE)) && (ENDPOINT_A0_FIFO[0] != 0b10000001 INTERFACE)) && (ENDPOINT_A0_FIFO[0] != 0b10000010 ENDPOINT))) { return; } switch (ENDPOINT_A0_FIFO[3]) { case 1 : //发送设备描述表。 发送数据 <= ENDPOINT_A0_FIFO[6,7] break; case 2 : //发送配置 [,接口(1),端点(1),接口(2),端点(2),...,类,厂商等] 描述表 break; case 3 : switch(ENDPOINT_A0_FIFO[2]) { case 0x00 : //发送字符串0描述表 break; case 0x01 : //发送字符串1描述表 break; default : return; } break; case 4 : //发送接口描述表 break; case 5 : //发送端点描述表 break; } } //设备描述表 const char USB_DEVICE_DESCRIPTOR[]= { UCHAR bLength ; UCHAR bDescriptorType ; USHORT bcdUSB ; UCHAR bDeviceClass ; UCHAR bDeviceSubClass ; UCHAR bDeviceProtocol ; UCHAR bMaxPacketSize0 ; USHORT idVendor ; USHORT idProduct ; USHORT bcdDevice ; UCHAR iManufacturer ; UCHAR iProduct ; UCHAR iSerialNumber ; UCHAR bNumConfigurations ; }; //配置描述表 const char USB_CONFIGURATION_DESCRIPTOR[]= { UCHAR bLength ; UCHAR bDescriptorType ; USHORT wTotalLength ; UCHAR bNumInterfaces ; . . UCHAR iConfiguration ; UCHAR bmAttributes ; UCHAR MaxPower ; }; //接口描述表 const char USB_INTERFACE_DESCRIPTOR[]= { UCHAR bLength ; UCHAR bDescriptorType ; UCHAR bInterfaceNumber ; UCHAR bAlternateSetting ; UCHAR bNumEndpoints ; UCHAR bInterfaceClass ; UCHAR bInterfaceSubClass ; UCHAR bInterfaceProtocol ; UCHAR iInterface ; }; //端点描述表 const char USB_ENDPOINT_DESCRIPTOR[]= { UCHAR bLength ; UCHAR bDescriptorType ; UCHAR bEndpointAddress ; UCHAR bmAttributes ; USHORT wMaxPacketSize ; UCHAR bInterval ; }; //字符串0描述表 const char USB_STRING_DESCRIPTOR[]= { UCHAR bLength ; UCHAR bDescriptorType ; WCHAR bLangID[1] ; .. } //字符串1描述表 const char USB_STRING_DESCRIPTOR[]= { UCHAR bLength ; UCHAR bDescriptorType ; WCHAR bString[1] ; } |
|
9楼#
发布于:2002-03-29 10:50
在发送配置 [,接口(1),端点(1),接口(2),端点(2),...,类,厂商等] 联合描述表时,各描述表的先后顺序可随意,主机USBD根据描述表类型标识区分各种分描述表。
描述表类型: USB_DEVICE_DESCRIPTOR_TYPE 0x01 USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 USB_STRING_DESCRIPTOR_TYPE 0x03 USB_INTERFACE_DESCRIPTOR_TYPE 0x04 USB_ENDPOINT_DESCRIPTOR_TYPE 0x05 |
|
10楼#
发布于:2002-03-29 13:20
//标准设备描述表
const char USB_DEVICE_DESCRIPTOR[]= { 0x12, // 描述表长18字节 0x01, // 设备描述表类型 0x10,0x01, // 此设备与描述表兼容的USB设备说明版本号(BCD 码) 0x00, // 设备类码 0x00, // 子类码 0x00, // 协议码 0x08, // 端点0的最大包大小(仅8,16,32,64为合法值) 0xb4,0x04,// 厂商ID(由USB标准付值) 0x70,0x63,// 产品ID(由厂商付值) 0x01,0x00,// 设备发行号(BCD 码) 0x01,// 描述厂商信息的字串描述表索引 0x02,// 描述产品信息的字串描述表索引 0x00,// 描述设备序列号信息的字串描述表索引(不支持设为0) 0x01,// 可能的设置描述表数 }; USB设备类码(UNKNOWN设为0): USB_DEVICE_CLASS_RESERVED 0x00 USB_DEVICE_CLASS_AUDIO 0x01 USB_DEVICE_CLASS_COMMUNICATIONS 0x02 USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 USB_DEVICE_CLASS_MONITOR 0x04 USB_DEVICE_CLASS_PHYSICAL_INTERFACE 0x05 USB_DEVICE_CLASS_POWER 0x06 USB_DEVICE_CLASS_PRINTER 0x07 USB_DEVICE_CLASS_STORAGE 0x08 USB_DEVICE_CLASS_HUB 0x09 USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF [编辑 - 3/29/02 作者: plasma] |
|
11楼#
发布于:2002-04-02 17:17
plasma是个好同志!!!
加油!!! |
|
|
12楼#
发布于:2002-04-04 14:20
USB设备启动流程:
1.USB设备接入USB口,发出连接USB命令 2.主机发出读设备描述符两次。 3.主机根据设备描述符――厂商ID、产品ID,启动相应设备驱动程序。 4.设备驱动程序初始化USB设备: a.读设备描述符 b.读配置描述符 c.选择接口、端点(管道),确定传输方式 |
|
13楼#
发布于:2002-04-04 14:28
D12固件驱动:
//指向外部D12访问地址 #define D12_COMMAND (*(unsigned char xdata *)0x8000) #define D12_DATA (*(unsigned char xdata *)0x0000) D12_COMMAND = 0xf3;D12_DATA = 0x0e;D12_DATA = 0x03;//初始化频率 12MHz D12_COMMAND = 0xd0;D12_DATA = 0x80;//设置地址 0 使能 D12_COMMAND = 0xf3;D12_DATA = 0x1e;//连接主机 |
|
14楼#
发布于:2002-04-04 14:32
D12_COMMAND = 0xf4;// 读中断寄存器
if(D12_DATA & 0x01)// 收到 SETUP 包 { D12_COMMAND = 0x40;//读 OUT 最后状态 if(D12_DATA & 0x20) { SETUP_read(); HandleSetup(); } } |
|
15楼#
发布于:2002-04-04 14:37
读D12缓冲区
unsigned char SetupBuf[8]; void SETUP_read(void) { unsigned char i; unsigned char * j; j = SetupBuf; D12_COMMAND = 0xf0;// 读标准控制码 *j = D12_DATA; *(j+1) = D12_DATA; for(i=0;i<8;i++) { *(j + i) = D12_DATA; } D12_COMMAND = 0xf1;// 应答SETUP包,使能(清 OUT 缓冲区、使能 IN 缓冲区)命令 D12_COMMAND = 0xf2;// 清 OUT 缓冲区 } |
|
16楼#
发布于:2002-04-04 14:39
写D12缓冲区
void USB_submit(void) { unsigned char i; D12_COMMAND = 0xf0;// 写缓冲区 D12_DATA = 0x00; D12_DATA = XmtBuff.bLength; for(i=0;i<16;i++) { D12_DATA = *(XmtBuff.p++); if (!--XmtBuff.bLength) { break; } } D12_COMMAND = 0xfa;// 设置 IN 缓冲区有效 } |
|
17楼#
发布于:2002-04-04 20:18
简单介绍一下D12好吗
对您的程序也做一下再详细点的功能说明好吗,这样我们初学者也可看懂一些. |
|
|
18楼#
发布于:2002-04-04 20:46
能给份电路图吗?
|
|
19楼#
发布于:2002-04-04 21:46
先介绍一下D12个管脚功能
1. D12的命令/数据切换有两种方式 a.将 ALE 接地,由A0进行命令/数据切换,A0 置 1 时可以向D12写命令,A0 置 0 时可以向D12写数据。这时可以将A0接P2口一个管脚(这里是A0接P27),通过读写外部数据时,发出的地址来将A0 置 1/置 0。 b.将 A0 接高电平,由ALE进行命令/数据切换,将D12的ALE接51的ALE(由D12的CS_N进行片选),当读写外部数据时,P0口发出奇数地址时,可向D12写入一个命令;P0口发出偶数地址时,可向D12读写数据。 2. D12的SUSPEND 当不能对D12操作时,不要忘了检查SUSPEND状态。如果SUSPEND为高表示D12已挂起,可将其置低,并发出恢复命令,唤醒主机。 3. D12的INT_N 可以说INT_N总是有效(由中断模式设置有关),一般D12挂起和忙时无效。 4. 与D12的DMA传输有关管脚 DMREQ 向51发出DMA请求,51可以DMA要求读写数据 DMACK_N 是51向D12确认DMA操作,D12完成DMA操作 EOT_N 是51向D12发出结束DMA操作,同时要求DMACK_N置低,并发出读或写的动作。 |
|
上一页
下一页