Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: как обработать установочный пакет usb
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
sergey sva
Разбираюсь с работой усб немного не понятно,с пакетами,
к примеру: программа приступила к обработки прерывания, определила какая конечная точка вызвала это прерывание,
определила, что поступил установочный пакет if (save_reg_csrX & AT91C_UDP_RXSETUP) {
какие действия нужно проделать дальше что бы обработать этот пакет? Или для at91sam7 его не надо обрабатывать?
aaarrr
Цитата(sergey sva @ Feb 10 2009, 17:30) *
какие действия нужно проделать дальше что бы обработать этот пакет?

Дальше нужно узнать, что от нас хочет хост, т.е. разобрать пакет в соответствии с разделом 9 (USB Device Framework) спецификации USB.
sergey sva
понятно , будем разбирать. smile.gif
Есть простой вопрос наверно по си, не хочется темы размножать с простыми вопросами, напишу здесь.
вот объявляем новый тип SetPacked который состоит из 8 байт:
Код
typedef struct{
BYTE  bmReqestType;
BYTE  bReqest;
DWORD wValue;
DWORD wIndex;
DWORD wLenght;
}SetPacked;

Вот еще объявляем? что то, как это будет работать не пойму, пример из книги Агурова.
Код
typedef union{
SetPacked  setup;
BYTE   b[8];
WORD  wREqest;
}usbSetPacked;

объясните если не затруднит.
aaarrr
Цитата(sergey sva @ Feb 10 2009, 19:20) *
вот объявляем новый тип SetPacked который состоит из 8 байт:

А DWORD у Вас - это short? Как-то нестандартно очень.

Цитата(sergey sva @ Feb 10 2009, 19:20) *
Вот еще объявляем? что то, как это будет работать не пойму, пример из книги Агурова.

Я бы не стал вообще заморачиваться структурами и юнионами для setup-пакета. Зачем?
rezident
Какой-то немного странный union, вы wREqest[4] может быть хотели написать? Но раз так написали, то в памяти переменные будут расположены следующим образом (если принять порядок следования как у "больших индейцев")
Код
1-й байт, смещение 0: bmReqestType    - b[0] - мл. байт wREqest
2-й байт, смещение 1: bReqest         - b[1] - ст. байт wREqest
3-й байт, смещение 2: мл.байт wValue  - b[2] - ничего
4-й байт, смещение 3: ст.байт wValue  - b[3] - ничего
5-й байт, смещение 4: мл.байт wIndex  - b[4] - ничего
6-й байт, смещение 5: ст.байт wIndex  - b[5] - ничего
7-й байт, смещение 6: мл.байт wLenght - b[6] - ничего
8-й байт, смещение 7: ст.байт wLenght - b[7] - ничего
sergey sva
Цитата
А DWORD у Вас - это short? Как-то нестандартно очень.

Опечатка вышла WORD там должен быть, unsigned short.
aaarrr
Цитата(rezident @ Feb 10 2009, 19:37) *
если принять порядок следования как у "больших индейцев"

А написано для little. Вот поэтому лучше работать с байтами, тем более, что их всего восемь, а поля в setup-пакете не меняются.
sergey sva
Вот набросал не большой разборщик установочного пакета, может что здесь нужно подправить ?
CODE

//-------------------------------------------------------------------------------
void PROCES_SETUP_PACKET(DWORD EP){
DWORD LenByt, n;
BYTE SetPacket[8];
WORD bReqest;
/* */
EP &=0x0F;
/* */
LenByt = (AT91C_BASE_UDP->UDP_CSR[EP] >> 16) & 0x07FF;
for (n = 0; (n < LenByt && n < 8); n++) {
SetPacket[n] = (BYTE) AT91C_BASE_UDP->UDP_FDR[EP];
}//end for
/* */
bReqest = SetPacket[0] & 0xFF ;
bReqest = (bReqest<<8) | (SetPacket[1] & 0xFF);
/* */
switch(bReqest){
case GET_STATUS_DEVICE:

break;
case GET_STATUS_INTERF:

break;
case GET_STATUS_ENDPNT:

break;
case GET_DESCRIPTOR_DEVICE:
case GET_DESCRIPTOR_INTERF:
case GET_DESCRIPTOR_ENDPNT:

break;
case GET_CONFIGURATION:

break;
case SET_CONFIGURATION:

break;
case SET_ADDRESS:

break;

default :

break;
}//end switch

}//end PROCES_SETUP_PACKET
//-------------------------------------------------------------------------------

aaarrr
Ну, это пока еще не разборщик smile.gif

Не вижу смысла объединять поля bmRequestType и bRequest в одной переменной - будет весьма неудобно работать.
sergey sva
Цитата
Ну, это пока еще не разборщик smile.gif

Будем потихоньку разбираться с этими разборщиками. smile.gif
Вот наваял для разборки запроса от хоста Get_stat_dev,
может что тоже нужно подправить, может в обращениях к регистрам что подправить?
CODE

//-------------------------------------------------------------------------------
void end_point_read(DWORD EP, BYTE *dat){
DWORD LenByt, n;
/* */
EP &=0x0F;
LenByt = (AT91C_BASE_UDP->UDP_CSR[EP] >> 16) & 0x07FF;
for (n = 0; n < LenByt; n++) {
*dat++ = (BYTE) AT91C_BASE_UDP->UDP_FDR[EP];
}//end for
/* */
}//end
//-------------------------------------------------------------------------------
DWORD end_point_write(DWORD EP, BYTE dat[], DWORD len) {
DWORD n;
/* */
EP &= 0x0F;
/* */
if (AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXPKTRDY) {
if ((DualBankEP & (1 << EP)) && (TxDataBank[EP] == 0)) {
TxDataBank[EP] = 1;
} else {
return 0;
}
}//end if AT91C_UDP_TXPKTRDY


for (n = 0; n < len; n++){
AT91C_BASE_UDP->UDP_FDR[EP] = dat[n];
}
AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_TXPKTRDY;
while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP));
AT91C_BASE_UDP->UDP_CSR[EP] &= ~AT91C_UDP_TXCOMP;
return len;
}
//-------------------------------------------------------------------------------
void Get_stat_dev(DWORD EP){
BYTE OPT[2];
EP &=0x0F;
/* */
OPT[0] = (POW_BUS | IGNOR_SIG);
OPT[1] = 0;
AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_DIR;

end_point_write(EP,OPT,2);

while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_RXSETUP));
AT91C_BASE_UDP->UDP_CSR[EP] &= ~AT91C_UDP_RXSETUP;
AT91C_BASE_UDP->UDP_CSR[EP] &= ~AT91C_UDP_DIR;
}//end void Get_stat_dev(void)
//-------------------------------------------------------------------------------

aaarrr
Цитата(sergey sva @ Feb 10 2009, 22:48) *
Вот наваял для разборки запроса от хоста Get_stat_dev,

Логичнее было бы начинать с GET_DESCRIPTOR.

Цитата(sergey sva @ Feb 10 2009, 22:48) *
может что тоже нужно подправить, может в обращениях к регистрам что подправить?

Обратите внимание на методику и последовательность установки/снятия битов регистра UDP_CSR в датшите. В частности, DIR нужно ставить до снятия RXSETUP и т.п.
sergey sva
исправил. Еще есть вопрос читаю по ходу книгу агурова, есть не ясность не большая, на картинке.Нажмите для просмотра прикрепленного файла
там функция getstatendpoint в ней объявляется переменная wIndex для чего она здесь?
aaarrr
Цитата(sergey sva @ Feb 11 2009, 17:14) *
для чего она здесь?

Наверное, осталась от copy-paste. Компилятор должен выдать ворнинг.
sergey sva
Вот функция которая записывает в конечную точку байты.:
CODE
//-------------------------------------------------------------------------------
DWORD end_point_write(DWORD EP, BYTE dat[], DWORD len) {
DWORD n;
/* */
EP &= 0x0F;
/* */
if (AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXPKTRDY) {
if ((DualBankEP & (1 << EP)) && (TxDataBank[EP] == 0)) {
TxDataBank[EP] = 1;
} else {
return 0;
}
}//end if AT91C_UDP_TXPKTRDY


for (n = 0; n < len; n++){
AT91C_BASE_UDP->UDP_FDR[EP] = dat[n];
}
AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_TXPKTRDY;
while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP));
AT91C_BASE_UDP->UDP_CSR[EP] &= ~AT91C_UDP_TXCOMP;
return len;
}
//-------------------------------------------------------------------------------

сначала здесь записываются в буфер конечной точки байты , после устанавливается флаг окончания записи,
далеше в цикле while ожидаю когда хост подтвердит получение байт, установкой флага AT91C_UDP_TXCOMP,
а если этого не произойдет, то программа зависнет в этом месте.
Как получше это обработать, может еще какие флаги проверять, или таймаут добавить ?
aaarrr
Цитата(sergey sva @ Feb 11 2009, 22:32) *
Код
  EP &= 0x0F;

Лучше сделать здесь реальную проверку, или не делать вообще.

Цитата(sergey sva @ Feb 11 2009, 22:32) *
Код
  TxDataBank[EP] = 1;

А где это сбрасывается?

Цитата(sergey sva @ Feb 11 2009, 22:32) *
Код
  AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_TXPKTRDY;

Обратите внимание на Warning в описании UDP_CSR. В данном случае он важен.


Цитата(sergey sva @ Feb 11 2009, 22:32) *
Код
  while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP));

Простым ожиданием TXCOMP убиваются все преимущества двойной буферизации.


Совет: не пытайтесь написать универсальные процедуры обслуживания конечных точек -
ничего, кроме лишнего геморроя, это не принесет.
sergey sva
решил немного с готовыми примерами разобраться, а то сложновато сразу разобраться.
В сети нашел пример usb hid, смотрю код, огромное количество структур объединений,
и прочей.., некоторый код даже не совсем понимаю как работает, вот например
Код
/* USB Common Descriptor */
typedef  struct _USB_COMMON_DESCRIPTOR {
  BYTE  bLength;
  BYTE  bDescriptorType;
}__attribute__ ((packed)) USB_COMMON_DESCRIPTOR;
эта структура описана в h файле.

этот код встречается в функции
Код
USB_COMMON_DESCRIPTOR * pD;
         (BYTE *) pD  +=  ((USB_CONFIGURATION_DESCRIPTOR *)pD)->wTotalLength;

при компиляции вылетает ошибка
Description Resource Path Location Type
lvalue required as left operand of assignment
И как этот оператор выполняется, что с чем складывается .?
aaarrr
Цитата(sergey sva @ Feb 12 2009, 22:05) *
И как этот оператор выполняется, что с чем складывается .?

Все вполне корректно: если pD содержит адрес USB_CONFIGURATION_DESCRIPTOR'а, то после этой операции он будет указывать на следующий после конфигурационной информации (всей, а не только дескриптора) байт. Зачем это надо - вопрос к автору.

А компилятор какой?
sergey sva
Цитата
А компилятор какой?

yagarto(GCC)

эта строчка тоже вызывает такую же ошибу
lvalue required as left operand of assignment Требуется какой то левый оператор
(BYTE *)pD += pD->bLength;
sergey sva
в процессе отправки репорта(дескриптора) проверяется кратный он размеру конечной точки или нет ,
если кратный то нужно оправлять пустой пакет. Пустой пакет нужно заполнять нулями или просто установить
флаг AT91C_UDP_TXPKTRDY ?
aaarrr
Цитата(sergey sva @ Feb 14 2009, 14:11) *
Пустой пакет нужно заполнять нулями или просто установить флаг AT91C_UDP_TXPKTRDY ?

Если пустой пакет заполнить нулями, то он автоматически перестанет быть пустым smile.gif Нужно просто взвести TXPKTRDY.
sergey sva
smile.gif
Еще появился вопрос smile.gif по поводу дескриптора конфигурации, он состоит
из дескрипторов, интерфеса конечных точек по запросу get descriptor что отправлять хосту весь
дескриптор конфигурации или только дескриптор конфигурации, тогда когда отправлять дескриптор интерфейса?
aaarrr
Отправлять надо все - дескриптор конфигурации, интерфейсов, конечных точек и т.д.
sergey sva
Пытался отправит полностью весь дескриптор конфигурации, но хост принимает(установкой TXCOMP) только первые 8 байт после, завивает в ожидание, может заметите что то неправильное.
на этой строчке while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP));
CODE

void get_deskriptor(DWORD EP,BYTE zap[]){
LONG lendes,n;
WORD lensen;
BYTE* des,FLAG_PACK = 0;
/* */
lensen = zap[7] & 0xFF;
lensen = (lensen<<8) | (zap[6] & 0xFF);
/* */

switch(zap[3]){
case DEVICE :
{
lendes = sizeof(USB_DeviceDescriptor);
des = (BYTE*) &(USB_DeviceDescriptor[0]);
break;
}
case CONFIGURATION:
{
lendes = sizeof(USB_ConfigurationDeskriptor);
des = (BYTE*) &(USB_ConfigurationDeskriptor[0]);
break;
}
case STRINGDESCRIPTOR:{
lendes = (sizeof(USB_StringDescriptor) - zap[2]);
des = (BYTE*) &(USB_StringDescriptor[zap[2]]);
}
case HIDDESCRIPTOR:{
lendes = sizeof(USB_HidDescriptor);
des = (BYTE*) &(USB_HidDescriptor[0]);
}
case REPORTDESCRIPTOR:{
lendes = sizeof(HID_ReportDescriptor);
des = (BYTE*) &(HID_ReportDescriptor[0]);
}
default:
{
stall(EP);
return;
}
}//end switch
/* --------------------------------------------------------- */
if(lensen > lendes){
if((lendes % 8) == 0 ){FLAG_PACK = 1;}else{FLAG_PACK = 0;}
}else{ lendes = lensen; } //end else
AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_DIR; // dev-> host


while(lendes > 8){
while(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXPKTRDY){}

for(n = 0; n < 8; n++){
AT91C_BASE_UDP->UDP_FDR[EP] = *(des++);
}//end for
AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_TXPKTRDY;
while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP));
// вот здесь программа зависает, первый раз отправляет 8
// байт с получает подтверждение TXCOMP , во второй раз зависает
// в ожидании TXCOMP

AT91C_BASE_UDP->UDP_CSR[EP] &= ~AT91C_UDP_TXCOMP;
lendes=lendes-8;
}//end while

if(FLAG_PACK == 1){
while(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXPKTRDY){}
AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_TXPKTRDY;
while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP));
AT91C_BASE_UDP->UDP_CSR[EP] &= ~AT91C_UDP_TXCOMP;
}else{
while(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXPKTRDY){}

for(n = 0; n < lendes; n++){
AT91C_BASE_UDP->UDP_FDR[EP] = *(des++);
}//end for
AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_TXPKTRDY;
while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP));
AT91C_BASE_UDP->UDP_CSR[EP] &= ~AT91C_UDP_TXCOMP;

}//end else
AT91C_BASE_UDP->UDP_CSR[EP] &= ~AT91C_UDP_DIR; // host-> dev
}//end get_deskriptor
//-------------------------------------------------------------------------------

Sergey Reva
Цитата(sergey sva @ Feb 14 2009, 17:36) *
..
Код
AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_TXPKTRDY;
      while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP));
      AT91C_BASE_UDP->UDP_CSR[EP] &= ~AT91C_UDP_TXCOMP;

..

Хочу обратить внимание, что при доступе к регистру UDP_CSR Atmel рекомендует использовать следующие макросы, хотя в своих же примерах их не использует smile.gif

doc6175.pdf (35.6.10 UDP Endpoint Control and Status Register)
Цитата
WARNING: Due to synchronization between MCK and UDPCK, the software application must wait for the end of the write
operation before executing another write by polling the bits which must be set/cleared.
//! Clear flags of UDP UDP_CSR register and waits for synchronization
#define Udp_ep_clr_flag(pInterface, endpoint, flags) { \
pInterface->UDP_CSR[endpoint] &= ~(flags); \
while ( (pInterface->UDP_CSR[endpoint] & (flags)) == (flags) ); \
}
//! Set flags of UDP UDP_CSR register and waits for synchronization
#define Udp_ep_set_flag(pInterface, endpoint, flags) { \
pInterface->UDP_CSR[endpoint] |= (flags); \
while ( (pInterface->UDP_CSR[endpoint] & (flags)) != (flags) ); \
}
Note: In a preemptive environment, set or clear the flag and wait for a time of 1 UDPCK clock cycle and 1peripheral clock cycle. However,
RX_DATA_BLK0, TXPKTRDY, RX_DATA_BK1 require wait times of 3 UDPCK clock cycles and 3 peripheral clock cycles
before accessin DPR.
aaarrr
И еще один момент: флаг RXSETUP должен быть сброшен после установки DIR. Не понятно, где это происходит у Вас.
sergey sva
Еще во время передачи дескриптора,
устанавливается бит DTGLE, так понял что этот бит устанавливается, когда хост прерывает передачу?
aaarrr
Цитата(sergey sva @ Feb 16 2009, 22:03) *
так понял что этот бит устанавливается, когда хост прерывает передачу?

Нет, он меняется после каждой успешной транзакции.
Sagittarius
Цитата(sergey sva @ Feb 14 2009, 18:36) *
Пытался отправит полностью весь дескриптор конфигурации, но хост принимает(установкой TXCOMP) только первые 8 байт после, завивает в ожидание, может заметите что то неправильное.


Это уже винда, она сначала считывает первые 8 байт дескриптора с размерами, потом у себя в кишках готовит буфер а на устройство выдает END_BUS_RES, после этого вычитывает дескриптор полностью. Ну и естественно все виснет по тому что не тот флаг ожидается. Сам долго с этим бился пока доку не прочитал :-)
sergey sva
Про END_BUS_RES не знал, добавил но ситуация такая же.
1 получаю установочный пакет, разбираю его, хост просит девайс дескриптор.
2 проверяю бит AT91C_UDP_TXPKTRDY и AT91C_UDP_RXSUSP
Код
while(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXPKTRDY){if( AT91C_BASE_UDP->UDP_ISR & AT91C_UDP_RXSUSP ) return;}

3 заполняю буфер , проверяю бит AT91C_UDP_TXCOMP , сбрасываю если надо.
Код
if (AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP) {
AT91C_BASE_UDP->UDP_CSR[EP] &= ~(AT91C_UDP_TXCOMP);
while (AT91C_BASE_UDP->UDP_CSR[0] & AT91C_UDP_TXCOMP);
}//end if

4 устанавливаю AT91C_UDP_TXPKTRDY
Код
AT91C_BASE_UDP->UDP_CSR[EP] |= AT91C_UDP_TXPKTRDY;

5 жду подтверждения получения хостом данных, или сброс, если сброс то вызываю функцию сброса.
Код
  while(!(AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_TXCOMP)){
            if (AT91C_BASE_UDP->UDP_CSR[EP] & AT91C_UDP_RX_DATA_BK0) {
                AT91C_BASE_UDP->UDP_CSR[EP] &= ~(AT91C_UDP_RX_DATA_BK0);
                return;
            }//end if
            if (AT91C_BASE_UDP->UDP_ISR & AT91C_UDP_ENDBUSRES){
                 reset_status = 1;
                 return;
            }//end bus reset
      }//end while

Ситуации в итоге такая: размер дескриптора конфигурации 18 байт, первые 8 он забирает с подтверждением,
следующие 8 байт не берет (подтверждения на них нет AT91C_UDP_TXCOMP) иногда присылает _ENDBUSRES,
но после сброса ситуация не меняется, берет первые 8 байт а вторую посылку нет подтверждения.
Работа с usb, что то вроде кота в мешке, что там происходит, установил монитор но он позволяет наблюдать
только после успешной конфигурации, может есть программы которые позволяет просмотреть что там происходит?
aaarrr
Цитата(sergey sva @ Feb 18 2009, 13:19) *
...берет первые 8 байт а вторую посылку нет подтверждения.

На поле wLength запроса на забили? Первый раз хост и просит 8 байт.
sergey sva
нет не забыл,
zap[8]; //установочный пакет.
/* */
lensen = zap[7] & 0xFF;
lensen = (lensen<<8) | (zap[6] & 0xFF);
/* */
Только просит не 8 байт а 64 почему то.
amw
Цитата(sergey sva @ Feb 12 2009, 21:05) *
Код
USB_COMMON_DESCRIPTOR * pD;
(BYTE *) pD  +=  ((USB_CONFIGURATION_DESCRIPTOR *)pD)->wTotalLength;

при компиляции вылетает ошибка
Description Resource Path Location Type
lvalue required as left operand of assignment
И как этот оператор выполняется, что с чем складывается .?

В gcc-4.x так уже нельзя делать.
Нужно
Код
USB_COMMON_DESCRIPTOR * pD;
/* Кстати чему pD равен в этом месте? */
BYTE *p = (BYTE *) pD;
p  +=  ((USB_CONFIGURATION_DESCRIPTOR *)pD)->wTotalLength;
pD = (USB_COMMON_DESCRIPTOR *)p;
sergey sva
Цитата
/* Кстати чему pD равен в этом месте? */

pD = (BYTE *) USB_ConfigDescriptor->bLength;
На нулевой элемент дескриптора конфигурации.
Атрибут __packed выравнивает адресс по байтам?Этот пример из rw , а какой атрибут использовать в gcc?
Код
typedef __packed struct _USB_CONFIGURATION_DESCRIPTOR {
  BYTE  bLength;
  BYTE  bDescriptorType;
  WORD  wTotalLength;
  BYTE  bNumInterfaces;
  BYTE  bConfigurationValue;
  BYTE  iConfiguration;
  BYTE  bmAttributes;
  BYTE  MaxPower;
} USB_CONFIGURATION_DESCRIPTOR;
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.