Написал hid-устройство в котором есть 2 конечные точки.
Interrupt IN работает как положено.
А вот с Interrupt OUT проблема - не могу понять как правильно обслуживать эту ping-pong конечную точку.
Пр возникновении прерывания от EP2 проверяю флаги AT91C_UDP_RX_DATA_BK0 и AT91C_UDP_RX_DATA_BK1.
Если они != 0 то читаю буффер конечной точки и подтверждаю данные в том буффере в котором ожидаю их (определяется ep2CTRL.bank).
Так вот пакет какой-бы длины я не отправлял в конечную точку доходят только первые 37 байт (размер hid-репорта).
Данные которые должны были-бы попасть во второй банк конечной точки теряются.
Отображаю данные обратно через usb и вижу что первые 37 байт пакета принимаются в банк 0 и всё. Инициализирую посылку ещё раз - теперь первые 37 байт пакета принимаются в банк 1 и т.д. Т.е. у меня принимается только по 37 байт из пакета любой длины.
Перечитал всё что касается UDP и обслуживания таких конечных точек. Никаких особенностей не нашёл.
Может кто что подскажет по этому поводу...
CODE
/*************************************************/
__thumb void SET_CSR(unsigned int endpoint, unsigned int flags)
{
volatile unsigned int reg = AT91C_BASE_UDP->UDP_CSR[endpoint];
reg |= REG_NO_EFFECT_1_ALL;
reg |= flags;
AT91C_BASE_UDP->UDP_CSR[endpoint] = reg;
while ( (AT91C_BASE_UDP->UDP_CSR[endpoint] & (flags)) != (flags));
}
/*************************************************/
/*************************************************/
__thumb void CLR_CSR(unsigned int endpoint, unsigned int flags)
{
volatile unsigned int reg = AT91C_BASE_UDP->UDP_CSR[endpoint];
reg |= REG_NO_EFFECT_1_ALL;
reg &= ~flags;
AT91C_BASE_UDP->UDP_CSR[endpoint] = reg;
while ( (AT91C_BASE_UDP->UDP_CSR[endpoint] & (flags)) == (flags));
}
/*************************************************/
/****************************************/
__thumb void EP2_ReadPayload(unsigned int bk, unsigned int status)
{
unsigned int size;
size = ((status>>16) & 0xffff);
if((bk&0x01) == 0)
{
if(ep2CTRL.buff0_status == 0)
{
for(unsigned int i=0; i<size; i++)
{
ep2CTRL.buff0[i] = (unsigned char) AT91C_BASE_UDP->UDP_FDR[2];
}
ep2CTRL.index0 = size;
ep2CTRL.buff0_status = 1;
}
}
else
{
if(ep2CTRL.buff1_status == 0)
{
for(unsigned int i=0; i<size; i++)
{
ep2CTRL.buff1[i] = (unsigned char) AT91C_BASE_UDP->UDP_FDR[2];
}
ep2CTRL.index1 = size;
ep2CTRL.buff1_status = 1;
}
}
}
__thumb void ep2Handler(void)
{
unsigned int status = AT91C_BASE_UDP->UDP_CSR[2];
if ((status & AT91C_UDP_TXCOMP) != 0)
{
CLR_CSR(2, AT91C_UDP_TXCOMP);
}
if ((status & UDP_RXDATA) != 0)
{
AT91C_BASE_UDP->UDP_IDR = (1<<2);
TaskOn(task_usb_term);
if( (status & (AT91C_UDP_RX_DATA_BK0|AT91C_UDP_RX_DATA_BK1)) != 0)
{
if(ep2CTRL.bank == 0)
{
EP2_ReadPayload(0, status);
ep2CTRL.bank = 1;
CLR_CSR(2, AT91C_UDP_RX_DATA_BK0);
}
else
{
EP2_ReadPayload(1, status);
ep2CTRL.bank = 0;
CLR_CSR(2, AT91C_UDP_RX_DATA_BK1);
}
}
}
// STALL sent
if ((status & AT91C_UDP_STALLSENT) != 0)
{
CLR_CSR(2, AT91C_UDP_STALLSENT);
if (ep2CTRL.status != UDP_ENDPOINT_HALTED)
{
CLR_CSR(2, AT91C_UDP_FORCESTALL);
}
}
if ((status & AT91C_UDP_RXSETUP) != 0)
{
CLR_CSR(2, AT91C_UDP_RXSETUP);
}
}