Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: USB FIFO
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
toweroff
Делал передачу по USB на основе FIFO. Пока размер блока данных был не более буфера, все было хорошо. Теперь блок нужно увеличить, и посыпались потери пакетов...
Видятся две причины - кривая реализация 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;
    }


в функции отправки пакетов:
Код
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 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++;
}


сам механизм FIFO со счетчиками начала и конца, выделением индекса массива обкатаны еще со времен x51 и передачи по UARTу
есть подозрение, что при "забившейся" очереди приема пакетов (т.к. когда данные "выгребаются" оттуда шустро, то все работает) некорректно работает USB, скорее всего NACK или вообще не генерится, или как-то не так
Я пометил в прерывании для OUT Endpoint место, где (возможно) нужно что-то добавить... или NACK вообще в данном случае генерится аппаратно, пока буфер точки не освободится и не будет получена команда CMD_CLR_BUF...
Передача в точку IN работает корректно

Буду благодарен любым замечаниям и советам
Спасибо, что дочитали такой длинный папирус smile.gif
toweroff
Решилось запретом прерывания USB в начале функции отправки в очередь приема из очереди и разрешением в конце. Скорость не упала
Совсем мозг сплавился... sad.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.