Цитата
Хорошо, а без прерываний ваш код работает?
Без прерываний не пробовал. Писал сразу с использованием прерываний UDP.
Цитата
Косяк скорее не в прерывании, а в каком-нибудь косяке типа установки DIR после сброса RXSETUP или TXPKTRDY после сброса TXCOMP
Вот мой обработчик прерываний от Endpoint 0.
DIR у меня устанавливается один раз после приёма SETUP-пакета перед подтверждением прерывания.
TXPKTRDY перед подтверждением TXCOMP.
CODE
/*******************************************************************/
//обработчик прерывания от EP0
void ep0Handler(void)
{
unsigned int status = AT91C_BASE_UDP->UDP_CSR[0];
//PutString0("EP0 handler\r\n");
//in-трансакция - устройство шлёт данные на хост
if ((status & AT91C_UDP_TXCOMP) != 0)
{
PutString0("TXCOMP\r\n");
// EP0 в состоянии передачи?
if (epsCTRL[0].status == UDP_ENDPOINT_SENDING)
{
// проверяем завершение передачи
if(epsCTRL[0].tx_flag == 0)
{
epsCTRL[0].tx_flag = EP0_WritePayload(); //записываем следующий блок данных с проверкой статуса
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY; //устанавливаем флаг начала передачи
AT91C_BASE_UDP->UDP_CSR[0] &= ~AT91C_UDP_TXCOMP; //подтверждаем прерывание
}
else
{
//передача завершена
//переводим конечную точку в исходное состояние
epsCTRL[0].status = UDP_ENDPOINT_IDLE;
epsCTRL[0].pData = 0;
epsCTRL[0].totalLen = 0;
epsCTRL[0].sendLen = 0;
epsCTRL[0].tx_flag = 0;
//присваиваем устройству назначенный адрес
if(setAddr.flag)
{
setAddr.flag = 0;
SetAddress(setAddr.address); //устанавливаем назначенный адрес
}
PutString0("TX complet\r\n");
AT91C_BASE_UDP->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); //подтверждаем прерывание
}
}
else
{
// подтверждаем прерывание
PutString0("Error Wr\r\n");
AT91C_BASE_UDP->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); //подтверждаем прерывание
}
}
// OUT packet received
if ((status & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) != 0)
{
PutString0("UDP_RXDATA\r\n");
AT91C_BASE_UDP->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0|AT91C_UDP_RX_DATA_BK1);
}
// STALL sent
if ((status & AT91C_UDP_STALLSENT) != 0)
{
PutString0("STALLSENT\r\n");
AT91C_BASE_UDP->UDP_CSR[0] &= ~(AT91C_UDP_STALLSENT);
// If the endpoint is not halted, clear the STALL condition
if (epsCTRL[0].status != UDP_ENDPOINT_HALTED)
{
AT91C_BASE_UDP->UDP_CSR[0] &= ~(AT91C_UDP_FORCESTALL);
}
}
// принят setup-пакет
if ((status & AT91C_UDP_RXSETUP) != 0)
{
PutString0("RXSETUP:\r\n");
USBGenericRequest request; //структура хранения текущего запроса
//считываем setup-пакет
ep0ReadRequest(&request);
//определяем направление перед подтверждением приёма setup-пакета
if (GetDirection(&request) == USBGenericRequest_IN)
{
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_DIR;
}
//подтверждаем приём setup-пакета
AT91C_BASE_UDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP;
//передаём принятый пакет на обработку
ep0RequestHandler(&request);
}
}
/*************************************************/
Сама передача данных начинается таким образом:
Код
//------------------------------------------------------------------------------
//пересылка данных через EP0
//передаём указатель на данные и кол-во байт для передачи
char EP0_Write( const char *pData, unsigned int dLength)
{
//PutString0("EP0 send data\r\n");
//сохраняем указатель на данные, кол-во байт для пересылки
//и обнуляем счётчик переданных байт
epsCTRL[0].status = UDP_ENDPOINT_SENDING;
epsCTRL[0].pData = pData;
epsCTRL[0].totalLen = dLength; //всего байт на передачу
epsCTRL[0].sendLen = 0; //всего послано байт
epsCTRL[0].tx_flag = 0; //флаг того что передача завершена
//ожидаем готовности к передаче
while((AT91C_BASE_UDP->UDP_CSR[0]&AT91C_UDP_TXPKTRDY)==AT91C_UDP_TXPKTRDY);
epsCTRL[0].tx_flag = EP0_WritePayload(); //записываем блок данных
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY; //инициируем передачу
// разрешаем прерывание от конечной точки
//для EP0 оно разрешено всегда
AT91C_BASE_UDP->UDP_IER = 1 << 0;
return 1;
}
В процессе эксперементов обнаружил интересное явление.
Вот моя функция загрузки данных в фифо конечной точки.
CODE
/****************************************/
//запись блока данных в EP0
unsigned char EP0_WritePayload(void)
{
int int_path, fract_path;
//вычисляем целую часть от того сколько осталось послать
int_path = (epsCTRL[0].totalLen - epsCTRL[0].sendLen)/EP0_SIZE;
//AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_DIR;
if(int_path > 0)
{
//есть больше чем EP0_SIZE
for(unsigned char i=0; i<EP0_SIZE; i++)
{
AT91C_BASE_UDP->UDP_FDR[0] = *(epsCTRL[0].pData + epsCTRL[0].sendLen + i);
}
epsCTRL[0].sendLen += EP0_SIZE; //увеличиваем кол-во переданных байт на 8
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_DIR;
return 0; //признак - ещё не все данные переданы
}
else
{
//осталась часть пакета, если она больше 0 то дописываем байты и выдаём признак что это последняя передача
//иначе просто выдаём признак последняя передача чтобы послать пустой пакет
fract_path = (epsCTRL[0].totalLen - epsCTRL[0].sendLen)%EP0_SIZE; //вычисляем дробную часть от того сколько осталось послать
if(fract_path > 0)
{
//дописываем остаток пакета
for(unsigned char i=0; i<fract_path; i++)
{
AT91C_BASE_UDP->UDP_FDR[0] = *(epsCTRL[0].pData + epsCTRL[0].sendLen + i);
}
epsCTRL[0].sendLen += fract_path; //увеличиваем кол-во переданных байт на дробную часть
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_DIR;
}
return 1; //возвращаем признак что все данные переданы
}
}
В ней я принудительно устанавил флаг AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_DIR после загрузки данных.
Так вот если я устанавливаю этот флаг так как сейчас в функции (по веткам условия int_path > 0 и fract_path > 0 т.е. реально чтото записываю в фифо) то получаю такой лог запросов:
CODE
CONNECT PULLUP
Start of programm
WAKEUP or RXRSM
WAKEUP or RXRSM
ENDBUSRES
RXSUSP
WAKEUP or RXRSM
ENDBUSRES
RXSETUP:
80 06 00 01 00 00 40 00
EP0: new request - standart Get Descriptor Device
UDP_RXDATA
ENDBUSRES
RXSETUP:
00 05 01 00 00 00 00 00
EP0: new request - standart Set AddressTX complet
RXSETUP:
80 06 00 01 00 00 12 00
EP0: new request - standart Get Descriptor Device
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 02 00 00 09 00
EP0: new request - standart Get Descriptor Configuration
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 03 00 00 FF 00
EP0: new request - standart Get Descriptor String
TX complet
UDP_RXDATA
RXSETUP:
80 06 03 03 09 04 FF 00
EP0: new request - standart Get Descriptor String
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 02 00 00 FF 00
tring
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 01 00 00 12 00
EP0: new request - standart Get Descriptor Device
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 02 00 00 09 00
EP0: new request - standart Get Descriptor Configuration
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 02 00 00 29 00
EP0: new request - standart Get Descriptor Configuration
TX complet
UDP_RXDATA
RXSETUP:
00 09 01 00 00 00 00 00
EP0: new request - standart Set ConfigurationTX complet
RXSETUP:
21 0A 00 00 00 00 00 00
EP0: new request - unsupported
STALLSENT
RXSETUP:
81 06 00 22 00 00 60 00
EP0: new request - standart unsupported
STALLSENT
RXSETUP:
81 06 00 22 00 00 60 00
EP0: new request - standart unsupported
STALLSENT
RXSETUP:
81 06 00 22 00 00 60 00
EP0: new request - standart unsupported
STALLSENT
RXSUSP
Если же я устанавливаю флаг
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_DIR; перед каждым return
( для ветки int_path > 0 запись всегда осуществляется, а вот дробная часть пакета реально записывыается только если fract_path > 0 иначе формируется пакет нулевой длины ) то лог сокращается:
CODE
CONNECT PULLUP
Start of programm
WAKEUP or RXRSM
WAKEUP or RXRSM
ENDBUSRES
RXSUSP
WAKEUP or RXRSM
ENDBUSRES
RXSETUP:
80 06 00 01 00 00 40 00
EP0: new request - standart Get Descriptor Device
UDP_RXDATA
ENDBUSRES
RXSETUP:
00 05 01 00 00 00 00 00
EP0: new request - standart Set AddressTX complet
RXSETUP:
80 06 00 01 00 00 12 00
EP0: new request - standart Get Descriptor Device
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 02 00 00 09 00
EP0: new request - standart Get Descriptor Configuration
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 03 00 00 FF 00
EP0: new request - standart Get Descriptor String
TX complet
UDP_RXDATA
RXSETUP:
80 06 03 03 09 04 FF 00
EP0: new request - standart Get Descriptor String
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 02 00 00 FF 00
tring
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 01 00 00 12 00
EP0: new request - standart Get Descriptor Device
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 02 00 00 09 00
EP0: new request - standart Get Descriptor Configuration
TX complet
UDP_RXDATA
RXSETUP:
80 06 00 02 00 00 29 00
EP0: new request - standart Get Descriptor Configuration
TX complet
UDP_RXDATA
RXSETUP:
00 09 01 00 00 00 00 00
EP0: new request - standart Set ConfigurationTX complet
RXSUSP
Т.е. во втором логе отсутствуют запросы класса!!!
Но в обоих случаях проходит стабильная энумерация!!!
Логика подсказывает мне что нужно оставить установку флага
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_DIR; только после фактической записи в фифо. Хотелось бы услышать мнение знающих людей по всему что я тут написал