|
|
  |
SAM7x256 & USB |
|
|
|
Jul 19 2009, 07:40
|
Частый гость
 
Группа: Участник
Сообщений: 119
Регистрация: 3-07-06
Пользователь №: 18 528

|
Код на прием такой Код uint AT91F_UDP_Read(AT91PS_CDC pCdc, char *pData, uint length) { AT91PS_UDP pUdp = pCdc->pUdp; uint packetSize, nbBytesRcv = 0, currentReceiveBank = pCdc->currentRcvBank; if ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RX_DATA_BK0)||(pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RX_DATA_BK1)) { return 0;//то есть, если не было ни одного пакета принято, то просто выходим } while (length) { if ( !AT91F_UDP_IsConfigured(pCdc) ) break; if ( pUdp->UDP_CSR[AT91C_EP_OUT] & currentReceiveBank ) { packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, length); length -= packetSize; if (packetSize < AT91C_EP_OUT_SIZE) length = 0; while(packetSize--) pData[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT]; pUdp->UDP_CSR[AT91C_EP_OUT] &= ~(currentReceiveBank); if (currentReceiveBank == AT91C_UDP_RX_DATA_BK0) currentReceiveBank = AT91C_UDP_RX_DATA_BK1; else currentReceiveBank = AT91C_UDP_RX_DATA_BK0;</P> <P> } } pUdp->UDP_CSR[AT91C_EP_OUT] &= ~(AT91C_UDP_TXCOMP); pCdc->currentRcvBank = currentReceiveBank; return nbBytesRcv;</P> <P>} код на передачу Код uint AT91F_UDP_Write(AT91PS_CDC pCdc, const char *pData, uint length) { AT91PS_UDP pUdp = pCdc->pUdp; uint cpt = 0;</P> <P> if ((pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY)) { return 0;//если усб готово к передаче, то начинаем её } pUdp->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP); cpt = MIN(length, AT91C_EP_IN_SIZE); length -= cpt; while (cpt--) pUdp->UDP_FDR[AT91C_EP_IN] = *pData++; pUdp->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;</P> <P> while (length) { cpt = MIN(length, AT91C_EP_IN_SIZE); length -= cpt; while (cpt--) pUdp->UDP_FDR[AT91C_EP_IN] = *pData++; while ( !(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) ) if ( !AT91F_UDP_IsConfigured(pCdc) ) return length; pUdp->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP); while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP); pUdp->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY; } return length; } в основном цикле я поочередно вызываю сначала чтение, потом запись. И получается, что посылка отправляется только тогда, когда произойдет прием посылки. Если убрать чтение в основном цикле, то передача идет всегда. Почему так? Мне нужно принимать контроллером всего 2 байта, а передавать 256, друг за другом. Причем 2 байта могут быть посланы контроллеру не всегда. получается следующее Код pCDC.Read(&pCDC, ((char *) &data_comp), 2); if ((length>256)) { pCDC.Write(&pCDC, data, length); } обнаружилось, что данные все таки доходят до микроконтроллера, а вот он на комп ничего не отправляет. убирая строчку чтения, получаем, что данные на комп все таки идут
|
|
|
|
|
Oct 29 2009, 05:28
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Всем доброго времени суток. Не стал открывать новую тему, потому как название как раз для моей  С USB работал, поднимал на PDIUSBD12 по прерываниям, да и на ARM тоже по примерам от атмела (Без прерываний). Но вот с прерываниями затык полный, не получается. После подключения девайса: 1. Два раза AT91C_UDP_ENDBUSRES; 2. Прерывание от ЕР0. Хост делает запрос GET DEVICE DESCRIPTOR, отсылаю в прерывании первые 8 байт дескриптора устройства; 3. Прерывание AT91C_UDP_TXCOMP; Отсылаю вторые 8 байт; 4. Прерывание AT91C_UDP_RX_DATA_BK0; Пока что ничего с ним не делаю, просто очищаю флаг. 5. Прерывание от ЕР0. Хост делает запрос SET ADDRESS c полем wValue = 0!  ; Отсылаю нулевой пакет. 6. Прерывание AT91C_UDP_TXCOMP; Очищаю. Далее три раза то же самое, и "Устройство USB работает не правильно... бла-бла-бла". Дескриптор устройства верный, опробованный, объявлен между #pragma pack(align 8) (компилятор IAR 5.4). Перелопатил все темы форума, связанные с SAM7 и USB по прерываниям. Все вроде правильно делаю, но, похоже что то не доделываю.  Ниже код прерывания и записи в конечную точку. Код /***************************************************************************** Main UDP interrupt handler. ******************************************************************************/ static void ISR_Handler(void) { UINT32 isr; /* Read interrupt status register and check events */ isr = AT91C_BASE_UDP->UDP_ISR; /* USB bus reset event */ if(AT91C_UDP_ENDBUSRES & isr) { DBG_OUT("USB bus reset!\r\n"); /* Disable and clear all interruptions, reverting to the base state */ AT91C_BASE_UDP->UDP_IDR = MAXUINT32; AT91C_BASE_UDP->UDP_ICR = MAXUINT32; /* Reset all endpoints FIFOs */ AT91C_BASE_UDP->UDP_RSTEP = MAXUINT32; AT91C_BASE_UDP->UDP_RSTEP = 0; /* Reset EP0 to a basic control endpoint */ AT91C_UDP_CSR[0] = AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL; while (AT91C_UDP_CSR[0] != (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL)); /* Enable interrupt for control enpoint (0) events. Other interrupts get enabled as the enumeration process complete */ AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0; /* Enable the function endpoints, setting address 0, and return immediately. Given that we've just reset everything, there's no point in continuing. */ AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN; AT91C_BASE_UDP->UDP_TXVC = 0; /* Enable tranceiver */ USB_State.curr_cfg = 0; /* Clear current configuration */ }
/* Check endpoints events */ if(AT91C_UDP_EPINT0 & isr) EV_EP0Int(); AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_UDP; }
/******************************************************************************* Control endpoint interrupt event *******************************************************************************/ static void EV_EP0Int(void) { UINT32 csr; csr = AT91C_BASE_UDP->UDP_CSR[0]; /* Get endpoint status and check events */ /* A setup data packet has been sent by the host and is available in the FIFO */ if(AT91C_UDP_RXSETUP & csr) Enumerate(); /* Call USB routine (notify that setup paket received)*/ /* Receive Data from Bank's */ if(AT91C_UDP_RX_DATA_BK0 & csr) { DBG_OUT("ISR EP0 RX0\r\n"); UDP_EP_CLR_FLAG(0, AT91C_UDP_RX_DATA_BK0); /* Notify USB peripheral device that data have been read */ USB_State.tx_len[0] = 0; /* Stop Tx transfer */ } if(AT91C_UDP_RX_DATA_BK1 & csr) { DBG_OUT("ISR EP0 RX1\r\n"); UDP_EP_CLR_FLAG(0, AT91C_UDP_RX_DATA_BK1); /* Notify USB peripheral device that data have been read */ USB_State.tx_len[0] = 0; /* Stop Tx transfer */ } /* Host get data from device complete */ if(AT91C_UDP_TXCOMP & csr) { DBG_OUT("ISR Tx Comp\r\n"); /* The previous message received was SET_ADDR now that the computer ACK our send_null(), we can set this address for real */ if(USB_State.dev_addr > 0) { DBG_OUT("ISR: Set new address!\r\n"); AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN | USB_State.dev_addr; /* Set specified usb address in the controller */ AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN; /* Tell the controller that we are in addressed mode now */ USB_State.dev_addr = 0; } /* Send the following data */ if(USB_State.tx_len[0] > 0 && USB_State.tx_data[0] != NULL) UDP_EP_Write(0, USB_State.tx_data[0], USB_State.tx_len[0]); /* Send data */ UDP_EP_CLR_FLAG(0, AT91C_UDP_TXCOMP); /* Reset Tx complete */ } if(AT91C_UDP_ISOERROR & csr) { DBG_OUT("ISR EP0 ISO Err\r\n"); UDP_EP_CLR_FLAG(0, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR); } }
/******************************************************************************* Write data to endpoint *******************************************************************************/ void UDP_EP_Write(UINT8 ep, void *data, INT len) { P_UINT8 ptr; /* Get actual endpoint transfer size */ UINT32 p_size = USB_State.ep_size[ep];
/* If there is more data than can fit in a single packet, queue the rest up. */ if(len > p_size) { len -= p_size; USB_State.tx_data[ep] = (P_UINT8)data + p_size; USB_State.tx_len[ep] = len; } else { p_size = len; USB_State.tx_data[ep] = NULL; USB_State.tx_len[ep] = 0; } DBG_OUT("UDP_EP_Write: Send %d bytes: ", p_size); UDP_EP_SET_FLAG(ep, AT91C_UDP_DIR); while(AT91C_BASE_UDP->UDP_CSR[ep] & AT91C_UDP_TXPKTRDY); /* Push a packet into the USB FIFO, and tell the controller to send. */ ptr = (P_UINT8)data; while(p_size--) AT91C_UDP_FDR[ep] = *ptr++; UDP_EP_SET_FLAG(ep, AT91C_UDP_TXPKTRDY); if(AT91C_BASE_UDP->UDP_CSR[ep] & AT91C_UDP_TXCOMP) UDP_EP_CLR_FLAG(ep, AT91C_UDP_TXCOMP); }
/******************************************************************************* Stall endpoint *******************************************************************************/ void UDP_EP_Stall(UINT8 ep) { AT91C_BASE_UDP->UDP_CSR[ep] |= AT91C_UDP_FORCESTALL; } При приеме SETUP-пакета проверяю поле bmRequestType: Код if(req_type & USB_BMREQUEST_DIR_DEV_TO_HOST) UDP_EP_SET_FLAG(0, AT91C_UDP_DIR); /* Set IN direction for endpoint */
/* Notify USB peripheral device that data have been read */ UDP_EP_CLR_FLAG(0, AT91C_UDP_RXSETUP);
--------------------
|
|
|
|
|
Oct 29 2009, 13:06
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(aaarrr @ Oct 29 2009, 19:47)  Уж не по фронту ли с прерыванием работаете? Учитывая наличие DBG_OUT'ов, вероятность пропустить и сбросить событие в таком случае приближается к 100%. Да по фронту, а это критично? Взял просто из другого своего же модуля  . Код /* Init ISR */ AT91C_BASE_AIC->AIC_IDCR = 1 << AT91C_ID_UDP; /* Ensure interrupts are disabled before init */ AT91C_BASE_AIC->AIC_SVR[AT91C_ID_UDP] =(UINT32)ISR_Handler; AT91C_BASE_AIC->AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | AT91C_AIC_PRIOR_LOWEST; DBG_OUT пишет у меня во внутренний буфер, который я потом читаю, остановив МК: Код CHAR DBG_Buf[2048] = {0, }; int putchar(int c) { static INT idx = 0; P_CHAR ptr = DBG_Buf + idx++; *ptr = (CHAR)c; if(idx > 2048) idx = 0; return c; } Стоп... Да не по фронту же, а по высокому уровню...
--------------------
|
|
|
|
|
Oct 29 2009, 13:19
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(prottoss @ Oct 29 2009, 16:06)  Да по фронту, а это критично? Взял просто из другого своего же модуля  . Критично, разумеется, ибо потенциальный глюкодром. А для внутренних источников SAM'а вообще не имеет смысла. Цитата(prottoss @ Oct 29 2009, 16:06)  Стоп... Да не по фронту же, а по высокому уровню... Тогда нет нужды писать AIC_ICCR. Распечатку вывода можете привести? Желательно включить в него значение CSR EP0 на входе в EV_EP0Int(). Да, а это - Код if(AT91C_BASE_UDP->UDP_CSR[ep] & AT91C_UDP_TXCOMP) UDP_EP_CLR_FLAG(ep, AT91C_UDP_TXCOMP); - зачем в UDP_EP_Write? Нулевой пакет не ей посылаете?
|
|
|
|
|
Oct 29 2009, 14:19
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(aaarrr @ Oct 29 2009, 20:19)  Распечатку вывода можете привести? Желательно включить в него значение CSR EP0 на входе в EV_EP0Int(). Распечатка: USB bus reset! USB bus reset! CSR: 0088804E Enumerate: req type: 08; req: 6; w_val: 100; w_idx: 0; w_len: 40; GetDescriptor Device. UDP_EP_Write Send 8 bytes. CSR: 00008081 ISR Tx Comp UDP_EP_Write Send 8 bytes. CSR: 00008082 ISR EP0 RX USB bus reset! CSR: 0088804E Enumerate: req type: 0; req: 5; w_val: 0; w_idx: 0; w_len: 0; SetAddress: 0. UDP_EP_Write Send 0 bytes. CSR: 00008081 ISR Tx Comp далее USB bus reset! и все по новой еще 2 раза. Цитата(aaarrr @ Oct 29 2009, 20:19)  Да, а это - Код if(AT91C_BASE_UDP->UDP_CSR[ep] & AT91C_UDP_TXCOMP) UDP_EP_CLR_FLAG(ep, AT91C_UDP_TXCOMP); - зачем в UDP_EP_Write? Нулевой пакет не ей посылаете? Извиняюсь, это осталось от разных предыдущих экспериментов - в коде этого нет, TX_COMP очищается вне этой процедуры, после ее вызова. Ну а вообще нулевые пакеты посылаются этой же процедурой...
--------------------
|
|
|
|
|
Oct 29 2009, 15:04
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(prottoss @ Oct 29 2009, 17:19)  Ну а вообще нулевые пакеты посылаются этой же процедурой... Обращение с битом DIR мне там не нравится, вот что о нем говорится в документации: Цитата This bit must be set before UDP_ CSRx/RXSETUP is cleared at the end of the setup stage. ... It is not necessary to check this bit to reverse direction for the status stage. Т.е. ставить его надо до сброса RXSETUP, а в случае ZLP - вообще не трогать, достаточно просто взвести TXPKTRDY.
|
|
|
|
|
Oct 29 2009, 15:31
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(aaarrr @ Oct 29 2009, 22:04)  Т.е. ставить его надо до сброса RXSETUP, а в случае ZLP - вообще не трогать, достаточно просто взвести TXPKTRDY. Я так и делаю, выше говорил об этом. То что поставил в процедуре записи - это для пробы. В одном из топиков по аналогичной проблеме так делал один товарисч http://electronix.ru/forum/index.php?showt...st&p=553036 как раз этой рекомендацией этот топик и заканчивается. Но это без толку в моем случае, хоть ставил в процедуре записи, хоть убирал комбинация одна. Запаршивает дескриптор устройтсва. Принимает первые 8 байт, сбрасывает шину и ставит адрес ноль...  Цитата(aaarrr @ Oct 29 2009, 22:26)  Угу, понятно. Покажите тогда обработку SET_ADDRESS. Поведение хоста говорит или о неправильной обработке Status Stage при установке адреса, или, например, о неправильной установке значения адреса. Что значит вот это: SetAddress: 0 Это значит что получен дескриптор: req type: 0; req: 5; w_val: 0; w_idx: 0; w_len: 0; Т.е., если я правильно понимаю, проблема до того, как хост посылает устройству этот запрос. А вообще обрабатывается SET_ADDRESS вот так: Код case USB_REQUEST_SET_ADDRESS: DBG_OUT("SetAddress: %d.", w_val); USB_State.dev_addr = w_val; /* Store new address */ UDP_EP_Write(0, 0, 0); /* Acked to host - send zero packet */ /* If the address change is to 0, do it immediately. */ if(!w_val) { AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN; AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN; } break;
--------------------
|
|
|
|
|
Oct 29 2009, 15:56
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Пардон, по невнимательности не понял источник проблемы  Здесь же дескрипторы хосту не уходят, будем копать в этом направлении. Вернемся к распечатке: Цитата USB bus reset! CSR: 0088804E Что-то подозрительное - RXBYTECNT=88, STALLSENT=1??? Цитата w_len: 40; - тоже странно, хотя и допустимо. XP сначала всегда просит 8 байт, что служит хостом в данном случае? Опубликуйте еще обработку запроса дескриптора, а лучше приаттачте всю USB-часть файлом.
|
|
|
|
|
Oct 29 2009, 16:16
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(aaarrr @ Oct 29 2009, 22:56)  Пардон, по невнимательности не понял источник проблемы  Здесь же дескрипторы хосту не уходят, будем копать в этом направлении. Вернемся к распечатке: Что-то подозрительное - RXBYTECNT=88, STALLSENT=1??? - тоже странно, хотя и допустимо. XP сначала всегда просит 8 байт, что служит хостом в данном случае? Опубликуйте еще обработку запроса дескриптора, а лучше приаттачте всю USB-часть файлом. Судя по прерываниям, первые 8 байт дескриптора хост читает, так как после отправки первых 8 байт я получаю TX_COMP. Вот после отправки вторых 8 байт я получаю RX_BK0, потом BUS_RESET, потом SET_ADDRESS 0. Дескриптор рабочий, стянут с другого устройства. В чем косяк не могу разобраться уже неделю. Вот исходник. Цитата(aaarrr @ Oct 29 2009, 22:56)  XP сначала всегда просит 8 байт, что служит хостом в данном случае? Не, Windows как раз просит 64 байта. Но после приема первых 8 обрубает диалог. Вроде все верно. Но должна дать адрес отличный от 0, что нет в моем случае... разбил уже лоб, не думал, что так тяжко будет  Хостом служит мой домашний РС с WinXP SP3 УУУпппссс! Сорри! Опечатка в листинге отладочных сообщений. Значение CSR не Цитата CSR: 0088804E Enumerate: req type: 08; req: 6; w_val: 100; w_idx: 0; w_len: 40; GetDescriptor Device. UDP_EP_Write Send 8 bytes. а Цитата CSR: 00088804 Enumerate: req type: 08; req: 6; w_val: 100; w_idx: 0; w_len: 40; GetDescriptor Device. UDP_EP_Write Send 8 bytes. Е влезло от последующего Enumerate.
Прикрепленные файлы
Sam7.rar ( 3.45 килобайт )
Кол-во скачиваний: 56
--------------------
|
|
|
|
|
Oct 29 2009, 17:10
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(sergeeff @ Oct 30 2009, 00:00)  В свое время, занимаясь отладкой USB на at91rm9200, да и на philips usdb12, убедился, что вставка отладочных printf'ов, нарушает временные ограничения на процесс usb enumeration и устройство не распознается. Так что, это не вариант. Я сообщал выше, что отладочные printf пишут во внутреннее ОЗУ, так что занимают времени не больше, чем сам процесс энумерации в прерывании. Если у Вас есть код работы USB-device (UDP) для at91rm9200, основанный на прерываниях, может поделитесь?  При первом взгляде на даташит на at91rm9200 не вижу разницы в устройстве блока UDP между at91rm9200 и at91sam7x256
--------------------
|
|
|
|
|
Oct 29 2009, 17:12
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(sergeeff @ Oct 29 2009, 20:00)  В свое время, занимаясь отладкой USB на at91rm9200, да и на philips usdb12, убедился, что вставка отладочных printf'ов, нарушает временные ограничения на процесс usb enumeration и устройство не распознается. Так что, это не вариант. Это смотря как printf организован. Нормальный вариант. 2 prottoss: Жжоте напалмом! Код w_val = (AT91C_BASE_UDP->UDP_FDR[0] & 0xFF); w_val = (AT91C_BASE_UDP->UDP_FDR[0] << 8); Ну и что будет в w_val?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|