mempfis_ 0 6 апреля, 2010 Опубликовано 6 апреля, 2010 · Жалоба Всем добрый вечер. На основе проекта usb-device-hid-transfer-project из примеров IAR 5.4 и собственных знаний по USB пишу своё HID-устройство. В цело половина этапа энумерации уже преодолена (реализована передача общих запросов, осталась передача запроса класса устройства). Но даже эта половина запросов работает нестабильно. В процессе энумерации host может 3 раза запросить device descriptor а потом перевести устройство в suspend (хотя я вижу что я отправил этот дескриптор). Или какой-либо другой дескриптор (но чаще именно на device descriptor). Или после запроса device descriptor наступает bus reset. Также бывает что все запросы (те которые уже реализованы) проходят гладко и у меня даже появляется неопознанное hid-устройство. Подозреваю что это косяки моей программы (пример из IAR вроде работает хотя и ужасно запутан) - возможно в реализации обработки прерываний от UDP. Интересует ссылка на какой-либо работающий (и не такой запутанный как иаровский) проект (под любой компилятор) с ипользованием USB в sam7s но обязательно с прерываниями. Хочу сравнить реализацию обработчика прерываний и найти "10 отличий". По-поводу своего проекта - помимо прерываний UDP используется PIT (раз в 1мС), USART0 (115200, в процессе энумерации через него выводятся различные сообщения), PIO (тоже по прерываниям но они практически не задействованы). Startup-код уверяет что возможны вложенные прерывания. Не может-ли большое кол-во источников прерываний и возможность вложенных прерываний влиять на процесс энумерации? Ведь некоторые этапы энумерации ограничены во времени а вложенные прерывания задерживаю работу обработчика прерываний UDP или чтото в этом духе. Вобщем буду благодарен всем кто даст ссылки на проекты или что-либо посоветут по организации работы UDP. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 6 апреля, 2010 Опубликовано 6 апреля, 2010 · Жалоба Интересует ссылка на какой-либо работающий (и не такой запутанный как иаровский) проект (под любой компилятор) с ипользованием USB в sam7s но обязательно с прерываниями. Хочу сравнить реализацию обработчика прерываний и найти "10 отличий". Хорошо, а без прерываний ваш код работает? Не может-ли большое кол-во источников прерываний и возможность вложенных прерываний влиять на процесс энумерации? Ведь некоторые этапы энумерации ограничены во времени а вложенные прерывания задерживаю работу обработчика прерываний UDP или чтото в этом духе. Ограничения 50-500мс. Не успеть нужно еще постараться. Косяк скорее не в прерывании, а в каком-нибудь косяке типа установки DIR после сброса RXSETUP или TXPKTRDY после сброса TXCOMP. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mempfis_ 0 7 апреля, 2010 Опубликовано 7 апреля, 2010 · Жалоба Хорошо, а без прерываний ваш код работает? Без прерываний не пробовал. Писал сразу с использованием прерываний UDP. Косяк скорее не в прерывании, а в каком-нибудь косяке типа установки DIR после сброса RXSETUP или TXPKTRDY после сброса TXCOMP Вот мой обработчик прерываний от Endpoint 0. DIR у меня устанавливается один раз после приёма SETUP-пакета перед подтверждением прерывания. TXPKTRDY перед подтверждением TXCOMP. /*******************************************************************/ //обработчик прерывания от 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; } В процессе эксперементов обнаружил интересное явление. Вот моя функция загрузки данных в фифо конечной точки. /****************************************/ //запись блока данных в 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 т.е. реально чтото записываю в фифо) то получаю такой лог запросов: 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 иначе формируется пакет нулевой длины ) то лог сокращается: 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; только после фактической записи в фифо. Хотелось бы услышать мнение знающих людей по всему что я тут написал :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 7 апреля, 2010 Опубликовано 7 апреля, 2010 · Жалоба Логика подсказывает мне что нужно оставить установку флага AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_DIR; только после фактической записи в фифо. Нет, не нужно. Почитайте в документации о правилах установки/сброса битов UDP_CSR. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kitsok 0 12 апреля, 2010 Опубликовано 12 апреля, 2010 · Жалоба Могу заслать работающий код - там FreeRTOS и USB Compisite device - HID joystick + custom. Только чур меня не спрашивать, что там и как, я уже и сам не помню ;) Если надо, отпишите в личку. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mempfis_ 0 12 апреля, 2010 Опубликовано 12 апреля, 2010 · Жалоба Спасибо Kitsok за желание помочь но со свои usb-устройством я уже разобрался :) Правда ещё почитаю про установку/сброс битов UDP_CSR (о чём говорил aaarrrr) чтобы окончательно всё довести до ума. Если ваш проект не секретный то выкладывайте сюда - думаю многим будет интересно посмотреть на него :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться