Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: SAM7x256 & USB
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
Timofey
Код на прием такой
Код
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);
}

обнаружилось, что данные все таки доходят до микроконтроллера, а вот он на комп ничего не отправляет. убирая строчку чтения, получаем, что данные на комп все таки идут
aaarrr
Код
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;//то есть, если не было ни одного пакета принято, то просто выходим
}

Здесь Вы выходите, если данные были приняты.
Timofey
Точно .... Мда, стыдно стало ...
Спасибо. Тема закрыта.
prottoss
Всем доброго времени суток. Не стал открывать новую тему, потому как название как раз для моейsmile.gif С 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! smile3046.gif ; Отсылаю нулевой пакет.
6. Прерывание AT91C_UDP_TXCOMP; Очищаю.

Далее три раза то же самое, и "Устройство USB работает не правильно... бла-бла-бла". Дескриптор устройства верный, опробованный, объявлен между #pragma pack(align 8) (компилятор IAR 5.4). Перелопатил все темы форума, связанные с SAM7 и USB по прерываниям. Все вроде правильно делаю, но, похоже что то не доделываю. unsure.gif Ниже код прерывания и записи в конечную точку.
Код
/*****************************************************************************
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);
aaarrr
В процедуре установки адреса криминала действительно не видно, но -
Код
    AT91C_BASE_AIC->AIC_ICCR  = 1 << AT91C_ID_UDP;

Уж не по фронту ли с прерыванием работаете? Учитывая наличие DBG_OUT'ов, вероятность пропустить и сбросить событие в таком случае приближается к 100%.
prottoss
Цитата(aaarrr @ Oct 29 2009, 19:47) *
Уж не по фронту ли с прерыванием работаете? Учитывая наличие DBG_OUT'ов, вероятность пропустить и сбросить событие в таком случае приближается к 100%.
Да по фронту, а это критично? Взял просто из другого своего же модуля laughing.gif .
Код
/* 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;    
}


Стоп... Да не по фронту же, а по высокому уровню...
aaarrr
Цитата(prottoss @ Oct 29 2009, 16:06) *
Да по фронту, а это критично? Взял просто из другого своего же модуля laughing.gif .

Критично, разумеется, ибо потенциальный глюкодром. А для внутренних источников 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? Нулевой пакет не ей посылаете?
prottoss
Цитата(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 очищается вне этой процедуры, после ее вызова.
Ну а вообще нулевые пакеты посылаются этой же процедурой...
aaarrr
Цитата(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.
prottoss
Цитата(aaarrr @ Oct 29 2009, 22:04) *
Т.е. ставить его надо до сброса RXSETUP, а в случае ZLP - вообще не трогать, достаточно просто взвести TXPKTRDY.
Я так и делаю, выше говорил об этом. То что поставил в процедуре записи - это для пробы. В одном из топиков по аналогичной проблеме так делал один товарисч smile.gif http://electronix.ru/forum/index.php?showt...st&p=553036 как раз этой рекомендацией этот топик и заканчивается. Но это без толку в моем случае, хоть ставил в процедуре записи, хоть убирал комбинация одна. Запаршивает дескриптор устройтсва. Принимает первые 8 байт, сбрасывает шину и ставит адрес ноль...sad.gif

Цитата(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;
aaarrr
Пардон, по невнимательности не понял источник проблемы sad.gif Здесь же дескрипторы хосту не уходят, будем копать в этом направлении.
Вернемся к распечатке:
Цитата
USB bus reset!
CSR: 0088804E

Что-то подозрительное - RXBYTECNT=88, STALLSENT=1???
Цитата
w_len: 40;

- тоже странно, хотя и допустимо. XP сначала всегда просит 8 байт, что служит хостом в данном случае?

Опубликуйте еще обработку запроса дескриптора, а лучше приаттачте всю USB-часть файлом.
prottoss
Цитата(aaarrr @ Oct 29 2009, 22:56) *
Пардон, по невнимательности не понял источник проблемы sad.gif Здесь же дескрипторы хосту не уходят, будем копать в этом направлении.
Вернемся к распечатке:
Что-то подозрительное - 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, что нет в моем случае... разбил уже лоб, не думал, что так тяжко будетsmile.gif

Хостом служит мой домашний РС с 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.
sergeeff
В свое время, занимаясь отладкой USB на at91rm9200, да и на philips usdb12, убедился, что вставка отладочных printf'ов, нарушает временные ограничения на процесс usb enumeration и устройство не распознается. Так что, это не вариант.
prottoss
Цитата(sergeeff @ Oct 30 2009, 00:00) *
В свое время, занимаясь отладкой USB на at91rm9200, да и на philips usdb12, убедился, что вставка отладочных printf'ов, нарушает временные ограничения на процесс usb enumeration и устройство не распознается. Так что, это не вариант.
Я сообщал выше, что отладочные printf пишут во внутреннее ОЗУ, так что занимают времени не больше, чем сам процесс энумерации в прерывании.
Если у Вас есть код работы USB-device (UDP) для at91rm9200, основанный на прерываниях, может поделитесь?smile.gif При первом взгляде на даташит на at91rm9200 не вижу разницы в устройстве блока UDP между at91rm9200 и at91sam7x256
aaarrr
Цитата(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?
sergeeff
Увы, я нанятый работник на частной фирме. Посему код принадлежит не мне, а работодателю.
prottoss
Цитата(aaarrr @ Oct 30 2009, 00:12) *
Жжоте напалмом!
smile.gif Спасибо
Цитата(aaarrr @ Oct 30 2009, 00:12) *
Код
    w_val = (AT91C_BASE_UDP->UDP_FDR[0] & 0xFF);
     w_val = (AT91C_BASE_UDP->UDP_FDR[0] << 8);

Ну и что будет в w_val?
получили младший байт, затем старший...
aaarrr
2 prottoss:

Еще присутствует косяк с передачей дескрипторов: если длина кратна размеру буфера, то в конце нужно передать ZLP, а в вашей реализации этого не делается.
Ну, ко всяким прочим "мелочам" придираться не буду, ладно уж sad.gif
prottoss
Цитата(sergeeff @ Oct 30 2009, 00:13) *
Увы, я нанятый работник на частной фирме. Посему код принадлежит не мне, а работодателю.
Спасибо за правдуsmile.gif Я же не прошу ВЕСЬ код.
aaarrr
Цитата(prottoss @ Oct 29 2009, 20:19) *
получили младший байт, затем старший...

...и старшим перетерли младший. Неужели не видите???
prottoss
Цитата(aaarrr @ Oct 30 2009, 00:20) *
Еще присутствует косяк с передачей дескрипторов: если длина кратна размеру буфера, то в конце нужно передать ZLP, а в вашей реализации этого не делается.
Ну, ко всяким прочим "мелочам" придираться не буду, ладно уж sad.gif
Ну код то отладочный пока, про нулевые пакеты в конце кратной передачи я в курсе. Так какой диагноз то, доктор?

Цитата(aaarrr @ Oct 30 2009, 00:22) *
...и старшим перетерли младший. Неужели не видите???
Аааааааааааа.... шайтан...

Все, заработало... cranky.gif crying.gif
aaarrr - Я Ваш должник по жизни cheers.gif
sergeeff
Мои наблюдения показали, что в atmel'овских процессорах чрезвычайно важно добиться четкого квитирования usb'ишных управляющих сигналов (т.е. записал нужный бит в нужный управляющий регистр - дождись, чтобы он действительно установился/сбросился), что в вышеприведенных примерах и имеет место. У меня все проблемы после этого благополучно разрешились.
aaarrr
Главное не наступить на грабли, любезно предоставленными фирмой Атмел в своих "библиотечках", не к ночи будь помянуты.
Использование такого вот макроса при разрешенных прерываниях может вызвать феерический глюкодром:
Код
// \brief  Clear flags in the UDP_CSR register and waits for synchronization
// \param  pUsb      Pointer to a S_usb instance
// \param  bEndpoint Index of endpoint
// \param  dFlags    Flags to clear
#define UDP_CLEAREPFLAGS(pUsb, bEndpoint, dFlags) { \
    while (!ISCLEARED(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags)) \
        CLEAR(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags); \
}
prottoss
Цитата(aaarrr @ Oct 30 2009, 04:10) *
Главное не наступить на грабли
Стараюсьsmile.gif Я вообще не пользую библиотеки от Атмела. Курю даташиты и тупо всю инициализацию пишу сам. Ляпы, правда, наподобие отсутствия палки перед равно иногда бывают...smile.gif
aaarrr
Цитата(prottoss @ Oct 30 2009, 00:30) *
Стараюсьsmile.gif Я вообще не пользую библиотеки от Атмела. Курю даташиты и тупо всю инициализацию пишу сам.

Это хороший, правильный подход smile.gif

Цитата(prottoss @ Oct 30 2009, 00:30) *
Ляпы, правда, наподобие отсутствия палки перед равно иногда бывают...smile.gif

А от них никто не застрахован. Хотя, например, в конструкции типа "A = B[0] | (B[1] << 8)" палку пропустить уже не получится.
mikki
Цитата(prottoss @ Oct 30 2009, 01:30) *
Курю даташиты и тупо ...

Большая просьба к форумчанам, не использовать подобного рода штампы (скрытая пропаганда курения!!!), при описании интеллектуальной работы с документацией. laughing.gif
AHTOXA
А фраза "чёрный кот" - скрытая пропаганда расизма, да? smile.gif
overloaded
Цитата(aaarrr @ Oct 30 2009, 00:10) *
Использование такого вот макроса при разрешенных прерываниях может вызвать феерический глюкодром:
.....
#define UDP_CLEAREPFLAGS(pUsb, bEndpoint, dFlags) { \
.....


А можно по подробнее пожалуйста, где такое чудо встречается? Я в USB Framework не нашел такого макроса..
prottoss
Цитата(overloaded @ Oct 31 2009, 10:23) *
А можно по подробнее пожалуйста, где такое чудо встречается? Я в USB Framework не нашел такого макроса..

Код
/* Clear flags of UDP UDP_CSR register and waits for synchronization */
#define UDP_EP_CLR_FLAG(ep, f) { AT91C_BASE_UDP->UDP_CSR[ep] &= ~(f); while(AT91C_BASE_UDP->UDP_CSR[ep] & (f)); }

/* Set flags of UDP UDP_CSR register and waits for synchronization */
#define UDP_EP_SET_FLAG(ep, f) { AT91C_BASE_UDP->UDP_CSR[ep] |= (f); while((AT91C_BASE_UDP->UDP_CSR[ep] & (f)) != (f)); }


Выдержка из даташита на SAM7X (В других AT91, имеющих на борту блок UDP)
Цитата
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. How-
ever, RX_DATA_BLK0, TXPKTRDY, RX_DATA_BK1 require wait times of 3 UDPCK clock cycles and 3 peripheral clock cycles
before accessing DPR.
overloaded
Это я какраз видел.. И этот насколько я понимаю нормальный в отличии от того что привел aaarrr(там постоянно пишем регистр а не раз записали и ждем его изменения). Вот и интересно где тот вариант встречается).
singlskv
Цитата(overloaded @ Oct 31 2009, 17:59) *
Вот и интересно где тот вариант встречается).
Например вот так в атмеловском Framework:
Код
///
/// !Macros
/// - CLEAR_CSR
/// - SET_CSR

/// Bitmap for all status bits in CSR.
#define REG_NO_EFFECT_1_ALL      UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 \
                                |UDP_CSR_STALLSENT   | UDP_CSR_RXSETUP \
                                |UDP_CSR_TXCOMP

/// Clears the specified bit(s) in the UDP_CSR register.
/// \param endpoint The endpoint number of the CSR to process.
/// \param flags The bitmap to set to 1.
#define SET_CSR(endpoint, flags) \
    { \
        volatile unsigned int reg; \
        reg = UDP_CSR(UDP_BASE,endpoint); \
        reg |= REG_NO_EFFECT_1_ALL; \
        reg |= (flags); \
        UDP_CSR(UDP_BASE,endpoint) = reg; \
        while ( (UDP_CSR(UDP_BASE,endpoint) & (flags)) != (flags)); \
    }

SET_CSR(...) вызываемая без запрета всех(или только нужных) прерываний гарантированно когда-нить зависнет...
aaarrr
Цитата(overloaded @ Oct 31 2009, 06:23) *
А можно по подробнее пожалуйста, где такое чудо встречается? Я в USB Framework не нашел такого макроса..

В какой-то старой версии framework. Новые не смотрел, ибо не интересно совершенно. Судя по коду, приведенному singlskv, они не многим лучше.
prottoss
Поднял наконец то на SAM7X USB полностью на прерываниях с программным FIFO на всех точках. RealTerm показывает около сотни килосимволов в секунду - устройство CDC с драйвером usbser.sys, Windows XP SP3. Убил сегодня выходной за изучением следующей проблемы. Если я устанавливаю для данных точки EP4 и EP5 с размером 256 байт, и передаю длинный файл (порядка нескольких мегабайт) после непродолжительного времени передача останавливается и хост больше с устройством не общается.
Если ставлю точки ЕР1 и ЕР2 размером по 64 байт - все ОК работает часами без зависонов.
Это фича usbser.sys или я опять где то палку не докинулsmile.gif ?

Увеличил размер буферов - поднял скорость то 220-230 килосимволов
aaarrr
Цитата(prottoss @ Nov 8 2009, 22:11) *
Это фича usbser.sys или я опять где то палку не докинулsmile.gif ?

Вообще, разницы не должно быть никакой. Впрочем, я никогда не использовал с usbser EP4-EP5, ввиду полной достаточности EP1-EP2.
prottoss
Цитата(aaarrr @ Nov 9 2009, 02:46) *
Вообще, разницы не должно быть никакой. Впрочем, я никогда не использовал с usbser EP4-EP5, ввиду полной достаточности EP1-EP2.
Где то я на форуме слышал про 256 байт для usbser.sys и какие то проблемы c этим. Хотя может и у меня в коде где то опять что то не то... С другой стороны, на 64 байт-точках все работает стабильно - уже пару гигабайт перелопатилось. Поставлю на ночь с рандомной генерацией размера пакета...
aaarrr
Цитата(prottoss @ Nov 8 2009, 22:52) *
Где то я на форуме слышал про 256 байт для usbser.sys и какие то проблемы c этим.

По спецификации размер bulk endpoint для full speed устройств ограничен 64 байтами. Может, там прямо так смело прописали 256?
prottoss
Цитата(aaarrr @ Nov 9 2009, 03:05) *
По спецификации размер bulk endpoint для full speed устройств ограничен 64 байтами. Может, там прямо так смело прописали 256?
Млин, точно... так и прописал smile3046.gif . Как Вы так угадываете все за 4000 километров? smile.gif Низкий Вам поклон.
prottoss
Продолжение темы.
Решил оптимизировать прием данных от хоста. Ранее я выгребал полностью данные из точки в софтовый ФИФО, а из него задача выгребала данных столько, сколько ей нужно. Решил избавиться от софтового буфера и забирать данные, сколько необходимо, сразу из конечной точки. При этом, если нужно данных меньше, чем находится в буфере точки, то не сбрасывать флаг приема (AT91C_UDP_RX_DATA_BK0/1) а просто запрещать прерывания. Что то опять туплю к выходным, ни как не выходит...

Описание конечной точки:
Код
/* Endpoint status setup */
typedef struct __UDP_EP_STATUS
{    
      INT size;        /* EP FIFO size */
    UINT32 type;    /* EP type (for store in CSR register) */
    UINT32 imask;    /* Interrupt flag in the IMR register (for enable/disable interrupt) */
    UINT32 banks;    /* Current receive bank for OUT endpoint, number of TX FIFO's for IN endpoint */
    
    P_UINT8 data;    /* Data buffer pointer */
    INT len;        /* Data size in buffer */
    INT inbuf;        /* For RX data count of buffered data */
    void (*fcbk)(void);    /* Optional transfer complete callback function */
    
} UDP_EP_STATUS, *P_UDP_EP_STATUS;


Обработчик прерывания по приему
Код
/* Receive Data from host host complete */
    if((AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) & csr)
    {    
        DBG_OUT("CSR%d RX: ", ep);
        if(p_eps->data)    /* Endpoint is in read state */
        {    
              if(p_eps->inbuf > 0)    /* Old EP FIFO not be fully readed */
                  cnt = p_eps->inbuf;
            else
                  cnt = (AT91C_UDP_RXBYTECNT & csr) >> 16;    /* Get data counter */
            
            if(p_eps->len >= cnt)    /* Room for new data exist */
            {
                p_eps->len -= cnt;    /* Add data to be readed */
                for(i = 0; i < cnt; i++)    /* Read new data */
                    *p_eps->data++ = AT91C_BASE_UDP->UDP_FDR[ep];
                p_eps->inbuf = 0;    /* No data in FIFO */
                ClrRxFlag(ep, p_eps);    /* Notify USB peripheral device that data have been read */
            }
            else    /* No room for all received bank */
            {    
                  p_eps->inbuf = cnt - p_eps->len;    /* Store number of bytes in EP FIFO */
                for(i = 0; i < p_eps->len; i++)    /* Read new data */
                    *p_eps->data++ = AT91C_BASE_UDP->UDP_FDR[ep];
                p_eps->len = 0;
            }
            
            /* Check read complete */
            if(!p_eps->len || cnt < p_eps->size)    /* OK */
            {
                p_eps->data = NULL;
                AT91C_BASE_UDP->UDP_IDR = p_eps->imask;    /* disable interrupt */
                if(p_eps->fcbk)    /* Call Rx Complete application callback */
                    p_eps->fcbk();
            }
        }
        else    /* Data buffer not set - application not wating data */
        {    
              DBG_OUT("NAK! Data buffer not set.\r\n");
            AT91C_BASE_UDP->UDP_IDR = p_eps->imask;    
        }
    }


Собственно попытка чтения
Код
/*******************************************************************************
Read data from endpoint
*******************************************************************************/
INT UDP_EP_Read(UINT8 ep, void *data, INT len, void (*fcbk)(void))
{    
      P_UDP_EP_STATUS p_eps;
        
    DBG_OUT("UDP_EP%d_Read: ", ep);
    
    if(!g_State.curr_cfg)    /* Check UDP device state */
    {    
          DBG_OUT("Device not configured!\r\n");
          return FALSE;    /* Not configured */
    }
    
    if(!ep || ep >= UDP_NUM_EP)    /* Check enpoint number */
    {    
          DBG_OUT("Invalid number %d!\r\n", ep);
          return FALSE;
    }
    
    p_eps = g_State.ep[ep];    /* Get endpoint status */
    if(!p_eps)    /* Check endpoint parameters */
    {    
          DBG_OUT("ep not inited!\r\n");
        return FALSE;
    }
    
    if(p_eps->data)
    {    
          DBG_OUT("ep busy!\r\n");
        return FALSE;
    }
    
    /* Set data fields */
    p_eps->data = data;
    p_eps->len = len;
    p_eps->fcbk = fcbk;
    
    AT91C_BASE_UDP->UDP_IER = p_eps->imask;        /* Enable interrupts from endpoint */
    DBG_OUT("\r\n");
    return TRUE;    /* Success */
}
aaarrr
Напишите, как оно по-вашему должно работать, и как работает на самом деле.
prottoss
Цитата(aaarrr @ Dec 12 2009, 20:01) *
Напишите, как оно по-вашему должно работать, и как работает на самом деле.
Спасибо, уже разобрался. Опять косяк с палочками былsmile.gif. Собственно, то что хотел, описал постом выше.
Когда я написал первый вариант драйвера - вычитывал все из буфера точки в буфер драйвера. А из буфера задача читала байт столько, сколько ей нужно было. Теперь решил оптимизировать и убрать буфер между драйвером UDP и задачей. Т.е. драйвер напрямую отдавал из хардварного FIFO конечной точки столько, сколько нужно задаче. Если в FIFO данные кончались, то флаг RX_BK0(1) очищался. Не работало в очередной раз по моей невнимательности.
Надеюсь понятно объяснил.
ZiB
Всем, день добрый!
Прошу извинить что не много не в "тему".
Решил попробовать USB, на макете запаял AT91SAM7S64 + обвязку.
Воспользовавшись примерами от Атмел, реализовал прием данных из МК в PC с конечной точкой 1 в режиме Bulk (длинна пакета 64 байта), получилось 64 000 байт в секунду, вроде как соответствует документации.
Можно ли получить большую скорость обмена?
aaarrr
Цитата(ZiB @ Dec 14 2009, 09:09) *
Можно ли получить большую скорость обмена?

Можно. Скорость в данном случае видимо ограничена хостовой частью (одна транзакция на фрейм).
sonycman
Цитата(ZiB @ Dec 14 2009, 10:09) *
Можно ли получить большую скорость обмена?

Bulk транзакции могут занимать всю свободную шину так, что за один фрейм их будет несколько.
На практике на STM32 с двойной буферизацией удаётся получить скорость около 900 килобайт в секунду, Mass Storage Class Device.
ZiB
Если я правильно понимаю, то для режима Bulk максимальная частота опроса (для full speed) составляет 1 кГц, а максимальная длина пакета 64 байта.
Устройства "Mass Storage Class Device" используют тип передачи Bulk, каким образом получается "900 килобайт в секунду"?
У STM32 High Speed USB?

В нашем колхозе доступны STM32F103VET6, ни разу с ними не работал. У них параметры USB одинаковы для всего семейства? (Reference Manual RM0008)
sonycman
Цитата(ZiB @ Dec 15 2009, 07:28) *
Если я правильно понимаю, то для режима Bulk максимальная частота опроса (для full speed) составляет 1 кГц, а максимальная длина пакета 64 байта.
Устройства "Mass Storage Class Device" используют тип передачи Bulk, каким образом получается "900 килобайт в секунду"?
У STM32 High Speed USB?

Транзакции bulk могут занимать всю свободную ширину шины USB.
За один фрейм (1мс) будет несколько передач.

900 килобайт - это Full Speed.
High Speed - это десятки мегабайт/сек.
ZiB
Ух, разобрался.
Согласно спецификации на USB 2.0 Full Speed максимальная пропускная способность канала в режиме Bulk 1 216 000 байт в секунду, у меня получилось чуть меньше, так как от начала фрейма до начала передачи есть не большая пауза.
Но для меня не так критично.
Сейчас летает гарантированно 512 000 байт в секунду, часик потестил smile.gif
Maximm
Цитата(ZiB @ Dec 15 2009, 12:50) *
Ух, разобрался.
Согласно спецификации на USB 2.0 Full Speed максимальная пропускная способность канала в режиме Bulk 1 216 000 байт в секунду, у меня получилось чуть меньше, так как от начала фрейма до начала передачи есть не большая пауза.
Но для меня не так критично.
Сейчас летает гарантированно 512 000 байт в секунду, часик потестил sm.gif



Это Вы получили такие скорости для CDC-устройства на драйвере usbser.sys?

Читал на форумах, что этот драйвер тормозной достаточно, и его заранее нужно нагружать из пользовательского приложения, чтобы хост запланировал больше транзакций....
kichnamid
Прошу прощения за вклинивание в эту тему, может, поможете.
Взял пример, идущий всместе с Keil'ом, передача данных черех HID-устройство для AT91SAM7S64. Переделал чуток дескриптор и отладил на SAM7256-EK плате.
При прошивке своего уже МК Windows не опознаёт USB-устройство. В проекте поменял только стартап в плане частоты и PLL, клок на UDP идёт правильный 48MHz.
В чём может быть подвох?
Maximm
Цитата(kichnamid @ Feb 2 2011, 14:24) *
Прошу прощения за вклинивание в эту тему, может, поможете.

В чём может быть подвох?


Схемы подключение шины USB к МК на вашей плате и на отладке аналогичные?
kichnamid
у меня к ножке DP сразу припаян пулап резистор. на отладочной схеме первоначально он подключался через транзистор, управляемый PA16 программно. но на отладочной я закоротил транзистор, и там теперь также как у меня. величины элементов взял один в один с отладочной.

единственный момент: у меня на USB разъёме перепутаны были 2 и 3 ножка, т.е. DP и DM цепи, но это исправил. всё равно устройство не распознаётся.

ещё заметил: если в стартапе к отладочному проекту отключить код для Flash-конроллера №0, устройство не опознаётся и на отладочной плате.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.