Page 1 of 1

1 ms too long for interrupts?

Posted: Fri Jun 26, 2015 11:43 pm
by ulao
I'm using a project that says one of its limits is

The transmit routine disables all interrupts while a byte is being transmitted. For a typical 9600bps link that is approximately 1 millisecond. In some cases this might cause problems with interrupts which need urgent attention.


Will v-usb handle this, I though I read 900us was a limit, some where?

Re: 1 ms too long for interrupts?

Posted: Sun Jun 28, 2015 9:28 am
by blargg
I thought that it was something like 27 cycles for an arbitrary disabling of interrupts. If you synchronize to USB packets, you can disable them longer. The keyboard I'm using right now is connected via V-USB with code that disables interrupts for almost 4ms every time it polls the keyboard. It's involved to synchronize though.

Re: 1 ms too long for interrupts?

Posted: Wed Jul 01, 2015 4:02 am
by ulao
Can you elaborate on this "If you synchronize to USB packets", this sounds interesting to me, unless you mean interrupt packets as a posed to bulk?

Re: 1 ms too long for interrupts?

Posted: Thu Jul 02, 2015 2:53 am
by blargg
The ADB protocol involves signal edges as often as every 25us, and V-USB's interrupt handler can take over 100us (and is cycle-timed, so cannot be interrupted). This requires that we synchronize with USB interrupts and do ADB transactions *between* them. Even doing ADB using the AVR's capture and PWM wouldn't work around this, due to the frequency of events relative to how long V-USB's interrupt handler can take. The USB interrupt packet comes every 8ms, leaving sufficient time for the 4ms of ADB polling/reply activity. Since USB packets for other devices can occur between this, usbdrv has been modified to set a global variable when our 8ms packet is received. This way we can disable interrupts between and ignore the other packets without error.

Image

When the host is updating a USB keyboard's LEDs, it sends these commands between the usual 8ms packets. These would be lost while doing ADB polling during that time. So the code waits a few ms after the 8ms packet for any more, before doing ADB polling. If it receives an LED change packet during that time, it skips ADB polling for that period and resumes after the next 8ms packet. See timing-leds.png: just after +10ms, the Num Lock key is pressed and the ADB poll receives that. Then the next 8ms USB packet comes in, followed by three more to change the LED state. ADB polling is skipped there. Then the next two normal ADB polls occur, and after +40ms the ADB commands to change the keyboard LED are sent.

Image

Re: 1 ms too long for interrupts?

Posted: Thu Jul 02, 2015 3:05 pm
by ulao
Why are you talking about the ADB protocol? What is really strange about this, is that I just wrote a firmware driver for ADB last week but I never mentioned that in this post? It's like you can read minds LOL... That is crazy coincidental, I was just talking to a guy that did the ADP keyboard thing, I was working with the pippin controller.

Anyways. "If you synchronize to USB packets, you can disable them longer" <-- now I see what you are talking about. Though yes that is a given. I was actually working with some code that tried to sleep the CPU at one point so that my work was always under the v-usb interrupts. I never did get it to work right.

"usbdrv has been modified to set a global variable when our 8ms packet is received." When did this occur? Ill have to look for that global but currently I just run the update code once a poll is over.

This issues is with a UART. I'm well aware that USB for windows is 8ms apart, 2ms for linux and there are hacks for windows. Though I was under the impression the interrupts were every 1ms~ or so. And trying to run a 9600 UART maybe be tricky with that. So your pretty much saying I can disable them as long as the usb does not poll?

cli();
update();//could take up to 6 ms with some of the updates I do.
sei();
while (!usbInterruptIsReady()) usbPoll();

Not sure that would work on linux?

Re: 1 ms too long for interrupts?

Posted: Thu Jul 02, 2015 11:20 pm
by blargg
That is crazy coincidental, I was just talking to a guy person that did the ADP keyboard thing, I was working with the pippin controller.


Haha, that was probably me.

This issues is with a UART. I'm well aware that USB for windows is 8ms apart, 2ms for linux and there are hacks for windows. Though I was under the impression the interrupts were every 1ms~ or so.


I'm on Linux (Ubuntu 12.04) and the packets to my device are only every 8ms (except when it sends several when updating the keyboard LEDs, and when first connecting the device). The USB interrupt is every 1ms, but no response is required between the 8ms packets.

And trying to run a 9600 UART maybe be tricky with that. So your pretty much saying I can disable them as long as the usb does not poll?


Here are hopefully the relevant parts of my code:

Code: Select all

uint8_t usbActivity;

int main( void )
{
   ...
   for ( ;; )
   {
      // Wait for 8ms USB interrupt packet
      usbActivity = false;
      do {
         usbPoll();
      }
      while ( !usbActivity );
   
      // Approximate time of USB interrupt
      unsigned frame_begin = clock();
   
      // Give USB plenty of time to do any more packets for this 8ms frame
      while ( clock_elapsed( frame_begin ) < CLOCK_US( 3500 ) )
         usbPoll();
   
      // If LEDs changed, do nothing for this frame as USB tends to be active throughout
      uint8_t new_leds = keyboard_leds;
      if ( old_leds != new_leds )
      {
         old_leds = new_leds;
         continue;
      }
   
      // Poll ADB keyboard
      cli();
      ... ~4ms
      sei();
   }
}


// Modification to usbdrv/asmcommon.inc

#define USB_CFG_ACTIVITY_FLAG 1

...
storeTokenAndReturn:
    sts     usbCurrentTok, token;[35]
#if ! USB_CFG_ACTIVITY_FLAG
doReturn:
#endif
doReturnNoActivity:
    POP_STANDARD                ;[37] 12...16 cycles
    USB_LOAD_PENDING(YL)        ;[49]
    sbrc    YL, USB_INTR_PENDING_BIT;[50] check whether data is already arriving
    rjmp    waitForJ            ;[51] save the pops and pushes -- a new interrupt is already pending
sofError:
    POP_RETI                    ;macro call
    reti
#if USB_CFG_ACTIVITY_FLAG
doReturn:
   ldi     x1, 1
    sts     usbActivity, x1
    rjmp    doReturnNoActivity
#endif

handleData:
#if USB_CFG_CHECK_CRC
    CRC_CLEANUP_AND_CHECK       ; jumps to ignorePacket if CRC error
#endif
    lds     shift, usbCurrentTok;[18]
    tst     shift               ;[20]
    breq    doReturnNoActivity  ;[21]
...

Re: 1 ms too long for interrupts?

Posted: Fri Jul 03, 2015 4:56 am
by ulao
So to get what you needed, you had to make changes to the asmcommon, interesting. Thx for sharing, I would guess that was not you, unless the initials SG mean anything to you.

Re: 1 ms too long for interrupts?

Posted: Fri Jul 03, 2015 5:45 am
by blargg
Yes, that was me helping a bit with your Pippin controller interfacing. I'd say that considering all the work I did to get V-USB working with something that required disabling interrupts, it would have made more sense to just use an atmega32u4 Arduino board that has hardware USB. I actually tried that approach too and it was simple, especially since the Teensy author had already written the USB keyboard code, so I just added my ADB code. Disable interrupts whenever, and it even supports 1ms USB polling for less latency.

Re: 1 ms too long for interrupts?

Posted: Fri Jul 03, 2015 4:36 pm
by ulao
Oh cool, yes I too considered that but I wanted to add ADB to my legacy code (328). BTW, I didn't make any special arrangements to the v-usb to get it to work but I also don't have to read a sh*t ton of keys and only needed 3 commands each update;)

FYI: I'm told linux will pull at 2ms with v-usb but you need to change the poll rate in the description.

Re: 1 ms too long for interrupts?

Posted: Sat Jul 11, 2015 1:30 am
by rsn8887
Concerning Windows 8ms delay between interrupts. I thought I can set that interval in the descriptor for endpoint 1 and endpoint 3, for example via the variable in usbconfig.h as such:

Code: Select all

#define USB_CFG_INTR_POLL_INTERVAL      8 //could set to 1 for 1 ms between polls
/* If you compile a version with endpoint 1 (interrupt-in), this is the poll
 * interval. The value is in milliseconds and must not be less than 10 ms for
 * low speed devices.
 */
 

or directly in the endpoint descriptor. But I have never really tested whether it becomes faster.

Re: 1 ms too long for interrupts?

Posted: Mon Jul 13, 2015 11:39 pm
by ulao
Right that is where you change it but window will force 8ms. You need to hack the sys file to allow fast pole times.