Does usbPoll() get executed before entry to the ISR?

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
stf92
Rank 1
Rank 1
Posts: 21
Joined: Sat Jan 11, 2014 5:09 pm

Does usbPoll() get executed before entry to the ISR?

Post by stf92 » Tue Jan 14, 2014 2:12 pm

Hi: This is part of the main module running on the device (GNU C):

Code: Select all

int main(void)
{
  DDRB = 0x22;  // 0010 0010 PB1=SDA and PB5=SCL are output
  PORTB = 0x22; //SDA=SCL=1

  usbInit();
  sei();
  for(;;){              // main event loop
        usbPoll();
          }
  return 0;
}


At device insertion (attachment), after a certain time the device rail voltage stabilizes. Then, two things happen: the device microcontroller is reset and the host (or hub) sends an SE0 to reset the device. The microcontroller, an ATtiny85 from Atmel, uses the ~RESET pin as an output. So, the reset mechanism is internal to the micro. Also, the device is not self-powered, so it uses the USB 5V and a low threshold 3.3V regulator to power the micro. Measuring time from when the USB supply reaches, say, 4.1V, there are two intervals: delta_t1, when the micro exits reset, and delta_t2, when an SE0 occurs on D-, D+ and the micro's INT0 pin is asserted. The interrupt service routine (ISR) in usbdrvasm.S begins execution as soon as sei() (above, code block) is executed. From the USB specification, revision 1.1, September 23, 1998, Figure 7-19, section 7.1.7.1:

Image

My question is: is there enough time for usbPoll() to complete execution for the first time before control goes to the ISR?

cpldcpu
Rank 2
Rank 2
Posts: 44
Joined: Sun Nov 10, 2013 11:26 am

Re: Does usbPoll() get executed before entry to the ISR?

Post by cpldcpu » Tue Jan 14, 2014 7:25 pm

>it uses the USB 5V and a low threshold 3.3V regulator

Can the Attiny 85 do 12 MHz at 3.3V? I am certain this is out of spec.

> is there enough time for usbPoll() to complete execution for the first time before control goes to the ISR?

If you clear pending interrupts before the SEI there may be. Otherwise the is most likely an interrupt pending and the ISR is called. You should mention what you are doing before the SEI.

stf92
Rank 1
Rank 1
Posts: 21
Joined: Sat Jan 11, 2014 5:09 pm

Re: Does usbPoll() get executed before entry to the ISR?

Post by stf92 » Wed Jan 15, 2014 12:03 pm

cpldcpu wrote:Can the Attiny 85 do 12 MHz at 3.3V? I am certain this is out of spec.

This is Yoshiyasu Takefuji's project, published in Circuit Cellar in issue no.213, year 2008, using Christian's driver. He arrived at the point (12MHz, 3.3V) by interpolation, I think. Anyway, I would like to draw attention towards the timing matter that I mentioned.
If you clear pending interrupts before the SEI there may be. Otherwise the is most likely an interrupt pending and the ISR is called. You should mention what you are doing before the SEI.

The device has just been plugged into the host port. What I do before the sei() is exactly depicted in the code block of post #1, which is ALL of the main function. I think you know what usbInit() does, do you?

cpldcpu
Rank 2
Rank 2
Posts: 44
Joined: Sun Nov 10, 2013 11:26 am

Re: Does usbPoll() get executed before entry to the ISR?

Post by cpldcpu » Sat Jan 18, 2014 6:53 am

It can be a good idea to simulate a device disconnect after program start to force a bus reset. This removes all ambiguity after startup.

Code: Select all

 usbDeviceDisconnect();  /* do this while interrupts are disabled */
 _delay_ms(500); 
  usbDeviceConnect();


Otherwise you should be more clear about what you actually want to accomplish with your code. Is there an actual issue or is this a general question?

stf92
Rank 1
Rank 1
Posts: 21
Joined: Sat Jan 11, 2014 5:09 pm

Re: Does usbPoll() get executed before entry to the ISR?

Post by stf92 » Sat Jan 18, 2014 12:23 pm

Well, it's really a pure theoretical question, but with a view to implement the data adquisition part of the program in hardware: bit reading and stuffing. This would let slow or old fashioned microprocessors to interface USB. My knowledge of USB started with the study of this program, which has led to understand the basics of the USB 1.1 specification. But now I see I would need at least 11 * 8 = 88-bit shift registers which kind of forces to use FPGA, and FPGA seems not to be do-it-your-self stuff. Now I see that, taking into account the high clock rates and large memory space of modern microcontrollers, a 2K software controller like the one object of this subforum is feasible (Christian's program of 2004 is 2KB long).

On the other hand, the Circuit Cellar project is up and running. It is just a MAX517 used as a programmable power source, programmble form a PC via USB and is up and running, save that I dispensed with the MAX517 and have a 33-ICs Z80 system reading the data sent by the device (all of them TTL small scale integration save RAM, ROM and CPU).

Anyways, useless as it is that knowledge in a ready-to-use world, I am quickly advancing in the comprehension of Christian's driver. To really understand it, I would need to make a state diagram of the program. And for this, a precise knowing of timing, fundamentally idle time between packages and the reset thing, is imperative.

The application program, main function is:

Code: Select all

int main(void)
{
  DDRB = 0x22;   // 0010 0010 PB1=SDA and PB5=SCL are output
  PORTB = 0x22;   //SDA=SCL=1

  usbInit();
  sei();
  for(;;){      // main event loop
       usbPoll();
     }
  return 0;
}

As you know, usbInit() unmasks INT0 interrupts ans sei() enables interrupts globally. When power is applied, let it be time t0, the ATtiny85 uC @12MHz is quickly running ready to accept interruptions. Whereas the host will spend in the order of hundreds of ms, counting from t0, to issue the reset signal. So I think usbPoll() will have a very pretty choice of executing all through before the interrupt service routine is entered. But that is not all. In usbdrv.c (2004 version, 12MHz clock), we have:

Code: Select all

static inline uchar   isNotSE0(void)
{
uchar   rval;
/* We want to do
 *     return (USBIN & USBMASK);
 * here, but the compiler does int-expansion acrobatics.
 * We can avoid this by assigning to a char-sized variable.
 */
   rval = USBIN & USBMASK;
   return rval;
}


and, in its usbPoll function:

Code: Select all

if(isNotSE0()){ /* SE0 state */
                usbIsReset = 0;
        }else{
                /* check whether SE0 lasts for more than 2.5us (3.75 bit times)
                if(!usbIsReset){
                        uchar i;
                        for(i=100;i;i--){
                                if(isNotSE0())
                                        goto notUsbReset;
                        }
                        usbIsReset = 1;
                        usbDeviceId = 0;
                        usbNewDeviceId = 0;
notUsbReset:;
                }
        }


This code makes shure to debounce the reset signal after attach and usbDeviceId and usbNewDeviceId get zeroed before entering the ISR, though as we discussed and another thread, their values are zero at this time as a result of the BBS section been zero at runtime. Does this line of reasoning seem plausible?

cpldcpu
Rank 2
Rank 2
Posts: 44
Joined: Sun Nov 10, 2013 11:26 am

Re: Does usbPoll() get executed before entry to the ISR?

Post by cpldcpu » Sat Jan 18, 2014 12:43 pm

Maybe the image below helps. It shows the USB traffic during device enumeration. "Int active" is high while the interrupt routine is executed, tx during set.

If you want to understand the usb protocol, i would recommend you get a logic analyzer with USB protocol support. The saleae support USB1.1 in it's newset beta.

Regarding external hardware: You could try to implement the bitstuffing and xor decoding in a small CPLD or even discrete logic. The you could use a UART or SPI to read the USB traffic which would unload the CPU a lot.

I am not sure why you are looking at an old version of the driver? The strange reset code is only there to make sure that the reset hook is not called multiple times during a reset, even if usbpoll() is called more than once.

Image

edit: man this forum really does not like images.

stf92
Rank 1
Rank 1
Posts: 21
Joined: Sat Jan 11, 2014 5:09 pm

Re: Does usbPoll() get executed before entry to the ISR?

Post by stf92 » Sun Jan 19, 2014 4:27 am

cpldcpu wrote:Maybe the image below helps. It shows the USB traffic during device enumeration. "Int active" is high while the interrupt routine is executed, tx during set.

If you want to understand the usb protocol, i would recommend you get a logic analyzer with USB protocol support. The saleae support USB1.1 in it's newset beta.

It helps, thank you.
Regarding external hardware: You could try to implement the bitstuffing and xor decoding in a small CPLD or even discrete logic. The you could use a UART or SPI to read the USB traffic which would unload the CPU a lot.

UART: great idea!
I am not sure why you are looking at an old version of the driver? The strange reset code is only there to make sure that the reset hook is not called multiple times during a reset, even if usbpoll() is called more than once.

That's precisely what debouncing is about. You can see bouncing at the end of the reset pulse in your oscilloscope (or logic analyzer, which one?) diagrams. As to version age, the more primitive the program the easiest its analysis. Above all, I'm trying learn.
[/quote]

blargg
Rank 3
Rank 3
Posts: 102
Joined: Thu Nov 14, 2013 10:01 pm

Re: Does usbPoll() get executed before entry to the ISR?

Post by blargg » Sun Jan 19, 2014 8:24 am

There shouldn't be any bouncing, as that's an artifact of mechanical switches. You may be thinking of ringing, but that's much more mild than switch bounce, and shouldn't get near logic thresholds so shouldn't affect the digital data. As I understand it, usbPoll() detects reset by one of the USB lines being in a non-idle state for an extended period of time. This condition is present for quite a while, so usbPoll() might notice it more than once before it ends. Thus, to avoid calling the user's reset hook more than once, it keeps track of whether it's already called it. The reason for usbPoll() having a loop that checks multiple times is that it needs to distinguish the line being active continuously, and it happening to catch it active during normal data transmission. In the latter, it toggles constantly between the active and idle states (which is the solid white parts you see in the image; if zoomed in you'd see lots of signal edges close together).

stf92
Rank 1
Rank 1
Posts: 21
Joined: Sat Jan 11, 2014 5:09 pm

Re: Does usbPoll() get executed before entry to the ISR?

Post by stf92 » Mon Jan 20, 2014 12:44 am

Yes, there is no bouncing in the oscillographs. I got distracted. I was speaking about the time when the device is plugged into the hub jack:

Code: Select all

deltat3: (TATTDB) This is a debounce interval with a minimum duration of 100ms that is provided by the USB
System Software. It ensures that the electrical and mechanical connection is stable before software
attempts to reset the attached device. The interval starts when the USB System Software is notified
of a connection detection. The interval restarts if there is a disconnect. The debounce interval
ensures that power is stable at the device for at least 100ms before any requests will be sent to the
device.

From the text explaining the figure in post #1, in the USB 1.1 specification.

cpldcpu
Rank 2
Rank 2
Posts: 44
Joined: Sun Nov 10, 2013 11:26 am

Re: Does usbPoll() get executed before entry to the ISR?

Post by cpldcpu » Tue Jan 21, 2014 9:53 am

The debounce interval is covered by the code is posted up here: viewtopic.php?f=8&t=8801&sid=166e80c1207f99a9e917f28d23023b3e#p26452

It is not necessary to take care of debouncing in the reset code. The code does exactly what I mentioned.

stf92
Rank 1
Rank 1
Posts: 21
Joined: Sat Jan 11, 2014 5:09 pm

Re: Does usbPoll() get executed before entry to the ISR?

Post by stf92 » Tue Jan 21, 2014 11:15 am

Well then next time I'll include a link to the sources Im working with. There is no DeviceDisconnect, DeviceConnect functions in them. Anyway, my concern was with respect to the thread title, and I now see I was the victim of a blunder (made by me). Now I see that the host interrupts the device (activates the INT0 pin) each SYNC. I'd forgotten the interrupts are set to edge triggered, positive edge. It is the first K in the SYNC that triggers the interrupts if unmasked and global enabled. This changes everything in my perspective.

By this time I'm busy with the usb_control_msg() function of libusb (linux). I see its parameters nearly match the ones in table 9-2 of USB specications 1.1 and 2.0, which by now I know well, with the exception of... What a pity! The bmRequestType is 0xC0, with the result that the type is type=vendor, and those specifications only cover standard device requests!

Post Reply