Page 1 of 1

[UPDATED] SetFeature problems

Posted: Sun Jun 07, 2009 12:01 am
by mschumann
UPDATE
Is it possible that my code is now too big that usbpoll() doesnt get called often enough? Is there a way to priorize usbpoll() over other code like the sei() I have in my timer1 routine that solved the other problem? Or could I call usbPoll in my timer2 overflow that drives my dcf77 with backup clock at 2kHz frequency. I could call usbPoll() every 50 rounds of that overflow what would make a call to usbPoll() every 25ms. Worst thing there would be that my backup clock could deviate some seconds and some DCF77 packets cannot be correctly decoded if usbPoll() what is irrelevant in my HTPC application. Are there any driver related side effect when using usbPoll() within a timer?
END UPDATE

Hi,
after getting a clone of the HidData Example up and running I ran into a new problem I ccould nots solve by now:
After several (10 to 80) setFeature Calls something happens to the usb stack (windows) and it will start responding
to every call (getFeature or setFeature) with this message (German): "Ein an das System angeschlossenes Gerät funktioniert nicht", code 1F.

getFeature works absolutely stable since I call it to poll with a 50ms timer without any problems. But I dont use usbFunctionRead, since I only need to transfer 8 Bytes. Vice versa 8 bytes would be enough too but I need to use usbFunctionWrite or is there an other way? Perhaps I missed something?

This is my USB Code:

Code: Select all

uchar   usbFunctionWrite(uchar *data, uchar len)
{
    if (usbremaining == 0) {
      for(uint8_t i=0; i<sizeof(usbrec); i++) usbrec[i] = usbrectmp[i];
        return 1;           
    }
    if (len > usbremaining) len = usbremaining;
    for (uchar i=0; i<len; i++) usbrectmp[usbcurraddr+i] = data[i];
    usbcurraddr += len;
    usbremaining -= len;
   return usbremaining == 0;
}


usbMsgLen_t usbFunctionSetup(uchar data[8])
{
usbRequest_t    *rq = (void *)data;

    if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {    /* HID class request */
      if (rq->bRequest == USBRQ_HID_GET_REPORT) { 
         if (command[0] != 0 && command[7] != 0) {
            for(uint8_t i=0; i<8; i++) commandtmp[i] = command[i];
            usbMsgPtr = commandtmp;
            command[0] = 0;
            command[2] = 0;
            command[7] = 0;
            return sizeof(command);
         } else
             commandtmp[0]=0;
            usbMsgPtr = commandtmp;
            return 1;
            
        } else if (rq->bRequest == USBRQ_HID_SET_REPORT) {
           
         usbremaining = rq->wLength.word;
         if (usbremaining  > USBRECBUFSIZE) usbremaining = USBRECBUFSIZE;
            usbcurraddr = 0;
         return USB_NO_MSG;
        }
    }
    return 0;
}


and this my device descriptor

Code: Select all

#define USBRECBUFSIZE 128
PROGMEM char usbHidReportDescriptor[22] = {    /* USB report descriptor */
    0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop)
    0x09, 0x01,                    // USAGE (Vendor Usage 1)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, USBRECBUFSIZE,           //   REPORT_COUNT = PUFFERGÖSSE
    0x09, 0x00,                    //   USAGE (Undefined)
    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
    0xc0                           // END_COLLECTION
};
static char usbrec[USBRECBUFSIZE], usbrectmp[USBRECBUFSIZE];


Re: [UPDATED] SetFeature problems

Posted: Sun Jun 07, 2009 8:48 pm
by christian
The rate of calling usbPoll() is not too critical. The 50 ms are required during device enumeration. But once it is initialized, calling it every several 100 ms should suffice to avoid errors. It's not sufficient from a performance point of view, of course.

If the device stalls at some point, I would suspect a problem with interrupt latency for the USB interrupt.

Re: [UPDATED] SetFeature problems

Posted: Sun Jun 07, 2009 10:57 pm
by mschumann
>> if the device stalls at some point, I would suspect a problem with interrupt latency for the USB interrupt.
What could cause such a latency? Do you have an idea? Here is some data:

- The device runs on 16MHz.
- I drive a GLCD and all code driving the display is in functions that are called within main(), so I have quite some code in my main loop.
- Data received via USB is also processed in a function that is called in main().
- I use Timer0 at 15kHz with a few lines (IR decoding) and have a sei() directly at the beginning
- I use Timer 2 at 2kHz also with a sei() at the beginning an also quite some code for decoding DCF77, a backup clock and setting status flags.

Code: Select all

for(;;)  { 
      // Infrarot
      processIR();
        // Anzeige
      processDisplay();
      // ON/OFF und MUTE
      processInternalCommands();
      // Kommandos vom Host
        processHostRequests();
      // USB bedienen
      usbPoll();

   }


I have invested so much work in this project that i plan to try the commercial way if i get it up and running and plan to aquire a (small) commercial vusb license.

Re: [UPDATED] SetFeature problems

Posted: Mon Jun 08, 2009 12:13 am
by mschumann
I think I have found the cause: After commenting out the dcf77 stuff (with lots of calculation) in timer2, no more errors occured. The DCF77 part was the first I did when getting aquainted with the ATMEGA so it is not very efficient and at that time I was not aware of potential timing issues. I will redesign it for the timer just to collect data and the calculation in an other routine in main().

I hope I am done now with the basics and can focus on the real thing: the logical part...

Re: [UPDATED] SetFeature problems

Posted: Mon Jun 08, 2009 10:32 am
by christian
Using sei() as the first instruction of the interrupt routine is not the best solution. It's better to declare the interrupt with attribute ISR_NOBLOCK (macro which expands to the gcc atribute __attribute__((interrupt))). Gcc will insert the sei automatically as the first instruction of your handler.

Note that this is not always possible. It works only for interrupts where the pending flag is auto-cleared when the handler is called. It does not work for UART rx and tx interrupts.