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?