Видятся две причины - кривая реализация FIFO и/или обработки прерывания...
Вот механизм FIFO (в двух массивах, в одном - данные, в другом - длины пакетов. Т.к. пакеты практически все максимальной длины (64 байта), то FIFO оперирует именно пакетами, а не байтами)
#define USB_MAX_PACKET 64
#define IBUF_LENGTH ((32*1024)/USB_MAX_PACKET)
#define IBUF_MASK (IBUF_LENGTH-1)
#define OBUF_LENGTH ((1*1024)/USB_MAX_PACKET)
#define OBUF_MASK (OBUF_LENGTH-1)
volatile U32 ibuf_start = 0;
volatile U32 ibuf_end = 0;
volatile U32 obuf_start = 0;
volatile U32 obuf_end = 0;
U32 BulkBufOut[OBUF_LENGTH][(USB_MAX_PACKET/sizeof(U32))];
U32 BulkBufIn[IBUF_LENGTH][(USB_MAX_PACKET/sizeof(U32))];
U32 BulkBufOutLengths[OBUF_LENGTH];
U32 BulkBufInLengths[IBUF_LENGTH];
volatile U32 isEPtransfer = 0;
в прерывании (проверки EP0 и флагов опущены... там вроде как все в порядке):
Код
/* OUT Endpoint */
if ((ibuf_start+IBUF_LENGTH) != ibuf_end)
{
BulkBufInLengths[ibuf_end & IBUF_MASK] = USB_ReadEP (MSC_EP_OUT, (U8*)&BulkBufIn[ibuf_end & IBUF_MASK][0]);
ibuf_end++;
}
//
// else - вопрос 1
//
//
//
/* IN Endpoint - transmit data */
if (obuf_end != obuf_start)
{
USB_WriteEP (MSC_EP_IN, (U8*)&BulkBufOut[obuf_start & OBUF_MASK][0], BulkBufOutLengths[obuf_start & OBUF_MASK]);
obuf_start++;
isEPtransfer &= ~DEVICE_SENDFULL;
}
else
{
isEPtransfer &= ~DEVICE_SENDACTIVE;
}
if ((ibuf_start+IBUF_LENGTH) != ibuf_end)
{
BulkBufInLengths[ibuf_end & IBUF_MASK] = USB_ReadEP (MSC_EP_OUT, (U8*)&BulkBufIn[ibuf_end & IBUF_MASK][0]);
ibuf_end++;
}
//
// else - вопрос 1
//
//
//
/* IN Endpoint - transmit data */
if (obuf_end != obuf_start)
{
USB_WriteEP (MSC_EP_IN, (U8*)&BulkBufOut[obuf_start & OBUF_MASK][0], BulkBufOutLengths[obuf_start & OBUF_MASK]);
obuf_start++;
isEPtransfer &= ~DEVICE_SENDFULL;
}
else
{
isEPtransfer &= ~DEVICE_SENDACTIVE;
}
в функции отправки пакетов:
Код
U32 USB_WriteBulkEP (U32 *pData, U32 cnt)
{
U32 n;
U32 *m;
while ((isEPtransfer & DEVICE_SENDFULL)==DEVICE_SENDFULL);
if ((isEPtransfer & DEVICE_SENDACTIVE)==DEVICE_SENDACTIVE)
{
BulkBufOutLengths[obuf_end&(OBUF_MASK)] = cnt;
m = (U32*)&BulkBufOut[obuf_end&(OBUF_MASK)][0];
obuf_end++;
if (((obuf_end ^ obuf_start)&OBUF_MASK)==0) isEPtransfer |= DEVICE_SENDFULL;
for (n = 0; n < (cnt + 3) / 4; n++)
{
*m++ = *pData++;
}
}
else
{
isEPtransfer |= DEVICE_SENDACTIVE;
USB_CTRL = ((MSC_EP_IN & 0x0F) << 2) | CTRL_WR_EN;
TX_PLENGTH = cnt;
for (n = 0; n < (cnt + 3) / 4; n++)
{
TX_DATA = *((__packed U32 *)pData);
pData++;
}
USB_CTRL = 0;
WrCmdEP(MSC_EP_IN, CMD_VALID_BUF);
}
return (cnt);
}
{
U32 n;
U32 *m;
while ((isEPtransfer & DEVICE_SENDFULL)==DEVICE_SENDFULL);
if ((isEPtransfer & DEVICE_SENDACTIVE)==DEVICE_SENDACTIVE)
{
BulkBufOutLengths[obuf_end&(OBUF_MASK)] = cnt;
m = (U32*)&BulkBufOut[obuf_end&(OBUF_MASK)][0];
obuf_end++;
if (((obuf_end ^ obuf_start)&OBUF_MASK)==0) isEPtransfer |= DEVICE_SENDFULL;
for (n = 0; n < (cnt + 3) / 4; n++)
{
*m++ = *pData++;
}
}
else
{
isEPtransfer |= DEVICE_SENDACTIVE;
USB_CTRL = ((MSC_EP_IN & 0x0F) << 2) | CTRL_WR_EN;
TX_PLENGTH = cnt;
for (n = 0; n < (cnt + 3) / 4; n++)
{
TX_DATA = *((__packed U32 *)pData);
pData++;
}
USB_CTRL = 0;
WrCmdEP(MSC_EP_IN, CMD_VALID_BUF);
}
return (cnt);
}
и прием пакетов:
Код
U32 USB_ReadBulkEP (U32 *pData) {
U32 n, cnt;
U32 *k;
// Wait for not empty buffer
while (ibuf_start == ibuf_end);
k = (U32*)&BulkBufIn[ibuf_start&(IBUF_MASK)][0];
cnt = BulkBufInLengths[ibuf_start&(IBUF_MASK)];
for (n=0; n < (cnt + 3) / 4; n++)
{
*pData++ = *k++;
}
ibuf_start++;
}
U32 n, cnt;
U32 *k;
// Wait for not empty buffer
while (ibuf_start == ibuf_end);
k = (U32*)&BulkBufIn[ibuf_start&(IBUF_MASK)][0];
cnt = BulkBufInLengths[ibuf_start&(IBUF_MASK)];
for (n=0; n < (cnt + 3) / 4; n++)
{
*pData++ = *k++;
}
ibuf_start++;
}
сам механизм FIFO со счетчиками начала и конца, выделением индекса массива обкатаны еще со времен x51 и передачи по UARTу
есть подозрение, что при "забившейся" очереди приема пакетов (т.к. когда данные "выгребаются" оттуда шустро, то все работает) некорректно работает USB, скорее всего NACK или вообще не генерится, или как-то не так
Я пометил в прерывании для OUT Endpoint место, где (возможно) нужно что-то добавить... или NACK вообще в данном случае генерится аппаратно, пока буфер точки не освободится и не будет получена команда CMD_CLR_BUF...
Передача в точку IN работает корректно
Буду благодарен любым замечаниям и советам
Спасибо, что дочитали такой длинный папирус
