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 get to simplify the code text to fit in just a couple of posts...
BYTE SUD[9]; BYTE ep3stall=0, ep2stall=0, ep1stall=0; BYTE RWU_enabled; bool USB_ini() { USB_IO(); SPI_ini(0); // software flags configval=0; // No configured PC_DTR=0; Suspended=1; // USB suspended RWU_enabled=0; // Set by host Set_Feature(enable RWU) request USB_rcv_length=0; USB_command_EOF=0; USB_send_length=0; USB_CSE; wreg(rPINCTL,(bmFDUPSPI+gpxOPERATE)); // MAX3420: SPI=full-duplex, INT=Edge Mode, POSINT=0(neg.edge xa menor consumo), GPX=OPERATE wreg(rUSBCTL,0); wreg(rCPUCTL,bmIE); // Enables the INT pin ENABLE_IRQS; USB_CSD; return TRUE; } void check_for_resume(void) { SPI_ini(0); USB_CSE; if(rreg(rUSBIRQ) & bmBUSACTIRQ) // THE HOST RESUMED BUS TRAFFIC Suspended=0; // no longer suspended USB_CSD; } void service_irqs(void) { if(SPI_mode==1){SPI_CLOSE;}if(SPI_init==0){SPI_ini(0);} USB_CSE; BYTE itest1,itest2; itest1 = rreg(rEPIRQ); // Check the EPIRQ bits itest2 = rreg(rUSBIRQ); // Check the USBIRQ bits if(itest1 & bmSUDAVIRQ) { wreg(rEPIRQ,bmSUDAVIRQ); // clear the SUDAV IRQ do_SETUP(); } if(itest1 & bmOUT1DAVIRQ) // Rcved EP1 (Bulk) TOS_post(USB_Rcv_Data); if((configval != 0) && (itest2&bmSUSPIRQ)) // HOST suspended bus for 3 msec { wreg(rUSBIRQ,(bmSUSPIRQ+bmBUSACTIRQ)); // clear the IRQ and bus activity IRQ Suspended=1; // signal the main loop } if(rreg(rUSBIRQ)& bmURESIRQ) wreg(rUSBIRQ,bmURESIRQ); // clear IRQ if(rreg(rUSBIRQ) & bmURESDNIRQ) { wreg(rUSBIRQ,bmURESDNIRQ); // clear IRQ bit Suspended=0; // in case were suspended ENABLE_IRQS; } USB_CSD; } void do_SETUP(void) { readbytes(rSUDFIFO,8,SUD); // got a SETUP packet switch(SUD[bmRequestType]&0x60) // Parse the SETUP packet { case 0x00: std_request(); break; case 0x20: class_request(); break; default: STALL_EP0 // unrecognized } } void std_request(void) { switch(SUD[bRequest]) { case SR_GET_DESCRIPTOR: send_descriptor(); break; case SR_SET_INTERFACE: set_interface(); break; case SR_GET_INTERFACE: get_interface(); break; case SR_GET_CONFIGURATION: get_configuration(); break; case SR_SET_CONFIGURATION: set_configuration(); break; case SR_SET_ADDRESS: rregAS(rFNADDR); break; // discard return value default: STALL_EP0 } } void set_configuration(void) { configval=SUD[wValueL]; if(SUD[wValueL]!=0) { wreg(rCLRTOGS,bmCTGEP3IN); // Clear toggle data EP3 IN (Interrupt) wreg(rCLRTOGS,bmCTGEP1OUT); // Clear toggle data EP1 OUT (Bulk) SETBIT(rUSBIEN, bmSUSPIE); // start looking for SUSPEND interrupts rregAS(rFNADDR); // dummy read to set the ACKSTAT bit } } void get_configuration(void) { wreg(rEP0FIFO,configval); // Send the config value wregAS(rEP0BC,1); } void set_interface(void) // All we accept are Interface=0 and AlternateSetting=0, otherwise send STALL { if((SUD[wValueL]==0) // wValueL=Alternate Setting index &&(SUD[wIndexL]==0)) // wIndexL=Interface index rregAS(rFNADDR); // dummy read to set the ACKSTAT bit else STALL_EP0 } void get_interface(void) // Check for Interface=0, always report AlternateSetting=0 { if(SUD[wIndexL]==0) // wIndexL=Interface index { wreg(rEP0FIFO,0); // AS=0 wregAS(rEP0BC,1); // send one byte, ACKSTAT } else STALL_EP0 }
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