USB function driver on freescale MXl

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



hello folks,

I'm developing a USB function driver (CDC-ACM class) on iMXl.
Everything went smooth until I found there were a problem when device
tried sending the configuration descriptor to a host. I realized that
when the device want to send the data through EP0 more than 32 bytes,
then it stop sending it and reset by the host. The firmware
implementation is very straightforward as you can see from below. Right
after it sees the Get_Descriptor request with configuration option, it
start send that corresponding descriptor which is 67 bytes total.
Because maximum size of EP0 FIFO is 32 bytes, I chopped the whole data
into three consecutive transfers. I believe there should be something
between each transfer to guarantee that each transfer is successful.

Happy Thanksgiving.....

Thanks in Advance,
Daein

++++++++++++++++++++++++
case CONFIGURATION: // 0x02
p = (unsigned char*)&ConfigDescSet;
//len = (U8) MIN_H(sizeof(Std_Config_descriptor),_gUsbDevReq[6]);
len = (U8) MIN_H(67,_gUsbDevReq[6]);

// Send the reply data.
iterate = (len / 32);
(len%32)?(iterate++):iterate;

while(iterate != 0)
{
fnSendEP0Data(p, len, &sentLen);
if (sentLen != 0) // if data were sent
successfully.
{
p += sentLen;
len -= sentLen;
iterate--;
}
// TESTING +++
//else
// break;
// TESTING ---
}
break;

-----------------------------------------

void fnSendEP0Data(unsigned char *pVoid, int length, int *sentLen)
{
int i, j;
int nNumPacket = length / EP0Len;
int tLen = 0;
int nRemaind=0;
unsigned char *pBuf = (unsigned char*)pVoid;
*sentLen = 0;

if(length==0)
return;

if(length % EP0Len)
nNumPacket++;

// USB FIFO data write is in big-endian format.
for(i=0; i<nNumPacket; i++)
{
// check how many bytes are left in EP0 FIFO
if ((((USB_EP0_STAT & (0x7F << 16)) >> 16) + EP0Len) > 32)
{
// check EOF
if (!(USB_EP0_INTR & (1<<2)))
{
continue;
}
else
{
*sentLen = tLen;
return;
}
}

if( ((pVoid-pBuf)+length) >= EP0Len)
{
USB_EP0_FDAT =
((*pBuf)<<24)|(*(pBuf+1)<<16)|(*(pBuf+2)<<8)|(*(pBuf+3));
USB_EP0_FCTRL |= 0x20000000; // next write is last one of
packet
USB_EP0_FDAT =
(*(pBuf+4)<<24)|(*(pBuf+5)<<16)|(*(pBuf+6)<<8)|(*(pBuf+7));
pBuf+=8;
tLen += 8;
}
else
// Packet size is less than EP0Len (8 bytes)
{
nRemaind = (pVoid-pBuf) + length;
if(nRemaind>=sizeof(U32))
{
if(nRemaind==sizeof(U32))
{
USB_EP0_FCTRL |= 0x20000000; // next write is last
one of packet
}


USB_EP0_FDAT=((*pBuf)<<24)|(*(pBuf+1)<<16)|(*(pBuf+2)<<8)|(*(pBuf+3));
pBuf+=4;
tLen += 4;
}

nRemaind=(pVoid-pBuf)+length;
for(j=0; j<nRemaind; j++)
{
if(j==(nRemaind-1))
{
USB_EP0_FCTRL |= 0x20000000; // next write is last
one of packet
}

*((volatile U8 *)((U32)&USB_EP0_FDAT+3)) = (U8)*pBuf;
pBuf++;
tLen += 1;
}
}

*sentLen = tLen;
}


//Checck if need to end with a zero length packet
if((!(length % EP0Len)) && (length != 8))
{
//SET_BITS(pEP0->STAT, USB_EPn_STAT_ZLPS, 1);
USB_EP0_STAT |= ZLPS_MASK; // next one is a zero length
packet
}

// Turn on SOF interrupt to signal CMD_OVER bit
//SET_BITS(pUSBDReg->USB_MASK, USB_MASK_SOF, 0);
if (length != 32)
USB_MASK &= ~(1<<6);
}

++++++++++++++++++++++++++++++++++++

.



Relevant Pages