Hello,
I'm using a MAX3420E in order to comm a PCB with Atmel microcontroller, with a PC using USB. In windows vista, the PC recognizes a Serial (Virtual) Port and works right, but when I try it in Windows XP, it seems that PC doesn't recognizes the device.
It appears in the device manager as "unknown device" with VID_0000&PID_0000...
I've been searching for a similar post, and found one that had the same problem VID_0000, but the last message does't give any solution...
Any clue? Thank you very much in advance.
The descriptors I use are list below:
// DESCRIPTORS const unsigned char DD[]= // DEVICE Descriptor {0x12, // bLength = 18d 0x01, // bDescriptorType = Device (1) 0x10,0x01, // bcdUSB(L/H) USB spec rev (BCD) 0x02,0x00,0x00, // bDeviceClass, bDeviceSubClass, bDeviceProtocol (descrito en Interface Descriptor) 0x40, // bMaxPacketSize0 EP0 is 64 bytes 0x6A,0x0B, // idVendor(L/H)--Maxim is 0B6A (2922 en decimal) 0x46,0x53, // idProduct(L/H)--5346 (21318 en decimal) 0x00,0x01, // bcdDevice--1234 1,2,3, // iManufacturer, iProduct, iSerialNumber 1}; // bNumConfigurations
const unsigned char CD[]= // CONFIGURATION Descriptor {0x09, // bLength 0x02, // bDescriptorType = Config 67,0x00, // wTotalLength(L/H) = Nº Bytes (67[0x43}) (Sin cabeceras 48[0x30]) 0x4300 0x02, // bNumInterfaces = 2 0x01, // bConfigValue 0x00, // iConfiguration 0xA0, // bmAttributes. b7=1 b6=NO self-powered b5=RWU supported (1 1 1 0 0 0 0 0) 0xFA, // MaxPower is 200 ma
// INTERFACE Descriptor 0x09, // length = 9 0x04, // type = IF 0x00, // InterFace Number = 0 0x00, // bAlternate Setting 0x01, // bNum Endpoints = 1 IN 0x02, // bInterfaceClass = 2 Communication 0x02, // bInterfaceSubClass = 2 0x01, // bInterfaceProtocol =1 (SubClass ACM=Abstract Control Mode, InterfaceProtocol=V.25ter, common AT commands) 0x00, // iInterface
// Header Functional Descriptor (marks beginning of the concatenated set of Functional Descriptors) 0x05, // bFunctionLength, Descriptor size in bytes --[18] --[48] 0x24, // bDescriptorType, CS_INTERFACE 0x00, // bDescriptorSubtype, Header Functional Descriptor 0x10,0x01, // bcdCDC, CDC specification release number in BCD format ([0x10, 0x01])
// Call Management Functional Descriptor 0x05, // bFunctionLength, Descriptor size in bytes 0x24, // bDescriptorType, CS_INTERFACE 0x01, // bDescriptorSubtype, Call Management Functional Descriptor 0x03, // bmCapabilities, Device doesn't call management itself (0->3) 0x01, // bDataInterface, Interface used for call management
// Abstract Control Management Functional Descriptor 0x04, // bDescriptorLength, Descriptor size in bytes 0x24, // bDescriptorType, CS_INTERFACE 0x02, // bDescriptorSubtype, Abstract Control Management Functional Descriptor 0x06, // bmCapabilities, Support for the GET/SET_LINE_CODING, BREAK & SET_CONTROL_LINE_STATE
// Union Functional Descriptor 0x05, // bFunctionLength, Descriptor size in bytes 0x24, // bDescriptorType, CS_INTERFACE 0x06, // bDescriptorSubtype, Union Functional Descriptor 0x00, // bMasterInterface, The controlling interface for the union (bInterfaceNumber of a Communication or Data Class interface in this configuration) 0x01, // bSlaveInterface0, The controlled interace in the union (bInterfaceNumber of an interface in this configuration)
Functional Descriptor***************** // Endpoint Descriptor EP3-IN 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x83, // bEndpointAddress (EP3 IN) 0x03, // bmAttributes (interrupt = 3) 0x40,0x00, // wMaxPacketSize (64[0x0040]) 0x02, // bInterval, Maximum latency (0x02)
// INTERFACE Descriptor 0x09, // length = 9 --[44] 0x04, // type = IF 0x01, // InterFace Number = 1 0x00, // bAlternate Setting 0x02, // bNum Endpoints = 2 (IN&OUT) 0x0A, // bInterfaceClass = A (Data) 0x00,0x00, // bInterfaceSubClass, bInterfaceProtocol (SubClass ACM=Abstract Control Mode, InterfaceProtocol=V.25ter, common AT commands) 0x00, // iInterface
// Endpoint Descriptor EP1-OUT 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x01, // bEndpointAddress (EP1-OUT) 0x02, // bmAttributes (bulk = 2) 0x40,0x00, // wMaxPacketSize (64[0x40]) 0x00, // bInterval (0x00)
// Endpoint Descriptor EP2-IN 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x82, // bEndpointAddress (EP2-IN) 0x02, // bmAttributes (bulk = 2) 0x40,0x00, // wMaxPacketSize (64[0x40]) 0x00, // bInterval (0x00) };
// STRING descriptors. An array of string arrays
const unsigned char strDesc[][64]= { // STRING descriptor 0--Language string { 0x04, // bLength 0x03, // bDescriptorType = string 0x09,0x04 // wLANGID(L/H) = English-United Sates }, // STRING descriptor 1--Manufacturer ID { 34, // bLength (0x2C para 23 (incluyendo tamaño y tipo??) 0x03, // bDescriptorType = string 'x',0, 'x',0, 'x',0, 'x',0, ' ',0, 'x',0, 'x',0, 'x',0, 'x',0, 'x',0, 'x',0, 'x',0, 'x',0, 'x',0, 'x',0, 'x',0,// text in Unicode }, // STRING descriptor 2 - Product ID { 8, // bLength 0x03, // bDescriptorType = string 'X',0, 'X',0, 'X',0, },
// STRING descriptor 3 - Serial Number ID { 8, // bLength 0x03, // bDescriptorType = string 'X',0, 'X',0, 'X',0, }};
const unsigned char SerialConf[]= { 0x00,0xE8,0x03,0x00, // dwDTFRate. Baudrate (9600hex->38400 baud) 0, // bCharFormat. 1 Stop bit 0, // bParityType: none 8, // Number of data bits: 8 };
I add thesecond part... First...I should have commented you that the program runs over API based on tinyOS (meshnetics), and the main bucle (my aplication) is called every Xms, I say 'X', because I can configures it with '0 ms' to make it runs 'as fast as possible'...but don't know the exact time. About the debug outputs, I just copy the variable's values meanwhile I debug.
void send_descriptor(void) { WORD sendlen,desclen; BYTE *pDdata=NULL; // pointer to ROM Descriptor data to send bool send_ZLP=FALSE; desclen = 0; // check for zero as error condition (no statements satisfied) switch (SUD[wValueH]) // wValueH is descriptor type { case GD_DEVICE: desclen = DD[0]; // descriptor length pDdata = (BYTE *) DD; break; case GD_CONFIGURATION: desclen = CD[2]; // Config descriptor includes interface, header and ep descriptors (67 Bytes [0x0043]) pDdata = (BYTE *) CD; break; case GD_STRING: desclen = strDesc[SUD[wValueL]][0]; // wValueL=string index, array[0] is the length pDdata = (BYTE *) strDesc[SUD[wValueL]]; // point to first array element break; case CS_INTERFACE: if(SUD[wIndexL]==0) // Interface Number=0. Del EndPoint 2 (interrupción), Communication { desclen = CD[9]; pDdata = (BYTE *) &CD[9]; } else if (SUD[wIndexL]==1) // Interface Number=1. Del EndPoint 1 (bulk), Datos { desclen = CD[44]; pDdata = (BYTE *) &CD[44]; } break; } // end switch on descriptor type // if (desclen!=0) // one of the case statements above filled in a value { sendlen = desclen; // Send Lower data if((desclen % 64) == 0) send_ZLP=TRUE; // Flag to send ZLP while(desclen>0) { if(desclen>64) sendlen=64; // if packet>64 bytes else sendlen=desclen; // if packet<=64 bytes while(!(rreg(rEPIRQ) & bmIN0BAVIRQ));// While out buff. isn't free writebytes(rEP0FIFO,sendlen,pDdata);// Write data in FIFO (EP_CONTROL) pDdata=(pDdata+sendlen); if(desclen<64) wregAS(rEP0BC,sendlen); // load EP0BC to arm the EP0-IN transfer & ACKSTAT else wreg(rEP0BC,sendlen); // load EP0BC to arm the EP0-IN transfer & ACKSTAT desclen-=sendlen; // Resta los datos ya enviados } if(send_ZLP) wregAS(rEP0BC,0); // load EP0BC to arm the EP0-IN transfer & ACKSTAT } else STALL_EP0; // none of the descriptor types match } void class_request(void) { switch (SUD[bRequest]) { case SEND_ENCAPSULATED_COMMAND: wregAS(rEP0BC, 0); break; // send_encapsulated_command(); break; case GET_ENCAPSULATED_RESPONSE: wregAS(rEP0BC, 0); break; // send_encapsulated_command(); break; // get_encapsulated_response(); break; case SET_COMM_FEATURE: break; case GET_COMM_FEATURE: break; case CLEAR_COMM_FEATURE:break; case SET_LINE_CONDING: { wregAS(rEP0BC, 0); // EnvÃa un paquete de longitud 0 para la etapa de 'STATUS' (?) if(SUD[wLengthL]>0) { while(!(rreg(rEPIRQ) & bmOUT0DAVIRQ) && SUD[7]<=5) SUD[7]++; readbytes(rEP0FIFO,SUD[wLengthL],(uint8_t *)&SUD[0]); // Lee la configuración serie por el EP0 (hay que cambiar algo para que lea?) } } break; case GET_LINE_CODING: { wregAS(rEP0BC, 0); // EnvÃa un paquete de longitud 0 para la etapa de 'STATUS' (?) writebytes(rEP0FIFO,SUD[wLengthL],(uint8_t *)&SerialConf[0]); wreg(rEP0BC, SUD[wLengthL]); } break; case SET_CONTROL_LINE_STATE: { if(configval) { USB_init=1; // Si llega a este punto, el dispositivo ha terminado de inicializarse if((SUD[wValueL]&0x01)==0x01)// PC listo para aceptar tramas del AZC PC_DTR=1; if(SUD[wValueL]==0x00) // Se ha cortado la comunicación con el PC PC_DTR=0; } wregAS(rEP3INBC, 0); } break; case SEND_BREAK: break; default: STALL_EP0; // none of the descriptor types match } } void wreg(BYTE reg, BYTE dat) { uint8_t data[2]; USB_CSE; data[0]=reg+2; data[1]=dat; spi_readWrite(data, 2); USB_CSD; } // Write a MAX3410E register with the "ACK STATUS" bit set in the command byte void wregAS(BYTE reg, BYTE dat) { uint8_t data[2]; USB_CSE; data[0]=reg+3; data[1]=dat; spi_readWrite(data, 2); USB_CSD; } // Read a register, return its value. uint8_t rreg(BYTE reg) { uint8_t dat[2]; dat[0]=reg; USB_CSE; spi_readWrite(&dat[0], 2); USB_CSD; return(dat[1]); } // Read a byte (as rreg), but also set the AckStat bit in the command byte. BYTE rregAS(BYTE reg) { uint8_t dat[2]; dat[0]=reg+1;; USB_CSE; spi_readWrite(&dat[0], 2); USB_CSD; return(dat[1]); } void readbytes(BYTE reg, BYTE N, uint8_t *p) { // uint8_t ind_read=0; p[0]=reg; USB_CSE; spi_readWrite(&p[0], N+1); USB_CSD *(uint64_t*)p=*(uint64_t*)(p+1); // for(ind_read=0;ind_read<N;ind_read++) // p[ind_read] = rreg(reg); } void writebytes(BYTE reg, BYTE N, uint8_t *p) { uint8_t ind_write=0; for(ind_write=0;ind_write<N;ind_write++) wreg(reg, p[ind_write]); }
"About the debug outputs, I just copy the variable's values meanwhile I debug."
I see.
As of your above code, - Bus reset handler is fine. No problem. - Unfortunately, you didn't include the super loop which calls service_irqs() The problem lies in the way how service_irqs() is called.
"I should have commented you that the program runs over API based on tinyOS (meshnetics), and the main bucle (my aplication) is called every Xms, I say 'X', because I can configures it with '0 ms' to make it runs 'as fast as possible'...but don't know the exact time."
I suppose service_irqs() is called from your "main bucle" using polling, like Maxim example. Is your tinyOS support interrupt? Then, move service_irqs() call to external INT pin ISR, which is connected to MAX3420E INT pin.
Tsuneo