cdb wrote: > > :: //Check if the endpoint has received any data from the host. > :: if(!USBHandleBusy(USBGenericOutHandle)) { > :: // ... USB OUT packet handling code goes here ... > :: } > > Out of interest, what happens if you move the function call out of the > IF statement and assign the result to a temporary variable? It's not a function call -- it's a macro: [usb_device.h] #define USBHandleBusy(handle) (handle==0?0:((volatile BDT_ENTRY*)handle)->STAT.UOWN) I can't see it having much difference, especially seeing as I'm already running C18 with optimisations off (ICD2 + debug build mode)... Also, the UOWN bit is inactive when the ICD2 breaks, so the if statement is doing what it's supposed to do... I've also just ruled out my own code by stripping ProcessIO down to this: > void ProcessIO(void) > { > int counter = 0; > unsigned char temp; > > //User Application USB tasks below. > //Note: The user application should not begin attempting to read/write over the USB > //until after the device has been fully enumerated. After the device is fully > //enumerated, the USBDeviceState will be set to "CONFIGURED_STATE". > if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; > > //As the device completes the enumeration process, the USBCBInitEP() function will > //get called. In this function, we initialize the user application endpoints (in this > //example code, the user application makes use of endpoint 1 IN and endpoint 1 OUT). > //The USBGenRead() function call in the USBCBInitEP() function initializes endpoint 1 OUT > //and "arms" it so that it can receive a packet of data from the host. Once the endpoint > //has been armed, the host can then send data to it (assuming some kind of application software > //is running on the host, and the application software tries to send data to the USB device). > > //If the host sends a packet of data to the endpoint 1 OUT buffer, the hardware of the SIE will > //automatically receive it and store the data at the memory location pointed to when we called > //USBGenRead(). Additionally, the endpoint handle (in this case USBGenericOutHandle) will indicate > //that the endpoint is no longer busy. At this point, it is safe for this firmware to begin reading > //from the endpoint buffer, and processing the data. In this example, we have implemented a few very > //simple commands. For example, if the host sends a packet of data to the endpoint 1 OUT buffer, with the > //first byte = 0x80, this is being used as a command to indicate that the firmware should "Toggle LED(s)". > if(!USBHandleBusy(USBGenericOutHandle)) //Check if the endpoint has received any data from the host. > { > if (USBHandleGetLength(USBGenericOutHandle) >= 1) { > switch(USBBuf_OUT[0]) //Data arrived, check what kind of command might be in the packet of data. > { > case 0x01: > for (temp=0; temp USBBuf_IN[temp] = USBBuf_OUT[temp]; > } > counter = USBHandleGetLength(USBGenericOutHandle); > break; > > case 0x02: > PORTB = USBBuf_OUT[1]; > break; > > default: > // Unknown command packet; ignore it. > break; > } > } > > //Now check to make sure no previous attempts to send data to the host are still pending. If any attemps are still > //pending, we do not want to write to the endpoint 1 IN buffer again, until the previous transaction is complete. > //Otherwise the unsent data waiting in the buffer will get overwritten and will result in unexpected behavior. > if (counter != 0) { > if(!USBHandleBusy(USBGenericInHandle)) > { > //The endpoint was not "busy", therefore it is safe to write to the buffer and arm the endpoint. > //The USBGenWrite() function call "arms" the endpoint (and makes the handle indicate the endpoint is busy). > //Once armed, the data will be automatically sent to the host (in hardware by the SIE) the next time the > //host polls the endpoint. Once the data is successfully sent, the handle (in this case USBGenericInHandle) > //will indicate the the endpoint is no longer busy. > USBGenericInHandle = USBGenWrite(USBGEN_EP_NUM,(BYTE*)&USBBuf_IN, counter); > } > } > > //Re-arm the OUT endpoint for the next packet: > //The USBGenRead() function call "arms" the endpoint (and makes it "busy"). If the endpoint is armed, the SIE will > //automatically accept data from the host, if the host tries to send a packet of data to the endpoint. Once a data > //packet addressed to this endpoint is received from the host, the endpoint will no longer be busy, and the application > //can read the data which will be sitting in the buffer. > USBGenericOutHandle = USBGenRead(USBGEN_EP_NUM,(BYTE*)&USBBuf_OUT,USBGEN_EP_SIZE); > } > }//end ProcessIO ... which is basically a stripped down version of the "remote-controllable LEDs" test. CMD 0x01 echoes the data from the OUT endpoint back to the IN endpoint, CMD 0x02 sets the state of the LEDs from the command's parameter byte. To simplify the code further, I turned ping-pong buffering off by altering these #defines: [usb_config.h] > //Make sure only one of the below "#define USB_PING_PONG_MODE" > //is uncommented. > //#define USB_PING_PONG_MODE USB_PING_PONG__NO_PING_PONG > #define USB_PING_PONG_MODE USB_PING_PONG__FULL_PING_PONG > //#define USB_PING_PONG_MODE USB_PING_PONG__EP0_OUT_ONLY > //#define USB_PING_PONG_MODE USB_PING_PONG__ALL_BUT_EP0 //NOTE: This mode is not supported in PIC18F4550 family rev A3 devices Now I've disabled ping-pong buffering (NO_PING_PONG uncommented), it works fine. It seems the ping-pong buffering introduces the "can't communicate after multiple SET_CONFIGs" bug... For now I've disabled ping-pong buffering, which seems to have solved the problem... Although I would rather have liked to have used PPB, if only for the mass transfer side of things (my application has to transfer ~500kbytes of data from an FPGA to the PC). *sigh*. Win some, lose some. Either way I'm filing a bug report with Microchip (not that I expect it to do any good). Thanks, -- Phil. piclist@philpem.me.uk http://www.philpem.me.uk/ -- http://www.piclist.com PIC/SX FAQ & list archive View/change your membership options at http://mailman.mit.edu/mailman/listinfo/piclist