Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Keil & AT91SAM7SXX & USB
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Sanya_kv
Приветствую всех!
Пашу на Keil и AT91SAM7SXX взял готовый пример из кейла c:\Keil\ARM\Boards\Atmel\AT91SAM7S-EK\USB\HID\ скомпилировал. Устройство в виндах появляется обмен с ним идет, но через какое-то время(0,5 - 2, 3 часа) устройство выпадает из конфигурации винды, причем в диспетчере устройств его нет. Минут через 5 говорит: устройство подключенное к USB работает не правильно... . При всем этом программа на процессоре работает. Сброса процессора не было. Кто-нибудь сталкивался с этой проблемой?
Заранее благодарен.
KAlex
Еще какие нибудь прерывания, кроме как для USB, используются?
Sanya_kv
Цитата(KAlex @ Jun 17 2009, 11:45) *
Еще какие нибудь прерывания, кроме как для USB, используются?

Уже ни каких, но проблема осталась.

Ощущение такое, что проходит сообщение по USB и библиотека его не отрабатывает, после чего и вылетает. Использую WinXP лицензионный со всеми паками.
KAlex
SPSR в IRQ_Handler_Entry обрабатывается?
Да и вообще, бездумное использование готовых примеров не есть гут.
Sanya_kv
Да. После сбоя в прерывание по USB больше не попадает. прога крутится в основном цикле. Хотя прерывания разрешены. Один раз было что зависло в цикле прерывания, но сглупил не отладил, сейчас хочу словить ещё раз эту ситуацию.
Sanya_kv
Разобрался с зависанием в функции прерывания USB_ISR.
Попадая в цикл while (isr = pUDP->UDP_ISR) { висит там до тех пор пока isr != 0
Код
void USB_ISR (void) /* __irq */{
  DWORD isr, csr, bkm, n;

  while (isr = pUDP->UDP_ISR) {

    /* End of Bus Reset Interrupt */
    if (isr & AT91C_UDP_ENDBUSRES) {
      USB_Reset();
      pUDP->UDP_ICR = AT91C_UDP_ENDBUSRES;
    }
   ...
   }

итог5е приходит прерывание AT91C_UDP_WAKEUP, обработки которого нет в цикле и сброса его не ведется, проблема решается добавлением pUDP->UDP_ICR = AT91C_UDP_WAKEUP;
AT91C_UDP_WAKEUP - приходит в момент подключения или отключения USB разъёма, но не всегда.

Но основная проблема ещё не решена. Тормозит редкость возникновения ошибки.
Неужели никто не сталкивался с такой проблемой?
KAlex
Что делает "USB_Reset();"
А если поменять ресет местами с "pUDP->UDP_ICR = AT91C_UDP_ENDBUSRES;"
Sanya_kv
Цитата(KAlex @ Jun 17 2009, 14:47) *
Что делает "USB_Reset();"
А если поменять ресет местами с "pUDP->UDP_ICR = AT91C_UDP_ENDBUSRES;"


Вот все тело функции:
Код
void USB_ISR (void) /* __irq */{
  DWORD isr, csr, bkm, n;

  while (isr = pUDP->UDP_ISR) {

   if (isr & AT91C_UDP_WAKEUP)
      pUDP->UDP_ICR = AT91C_UDP_WAKEUP;//Это моё

    /* End of Bus Reset Interrupt */
    if (isr & AT91C_UDP_ENDBUSRES) {
      USB_Reset();
#if   USB_RESET_EVENT
      USB_Reset_Event();
#endif
      pUDP->UDP_ICR = AT91C_UDP_ENDBUSRES;
    }

    /* USB Suspend Interrupt */
    if (isr & AT91C_UDP_RXSUSP) {
      USB_Suspend();
#if   USB_SUSPEND_EVENT
      USB_Suspend_Event();
#endif
      pUDP->UDP_ICR = AT91C_UDP_RXSUSP;
    }

    /* USB Resume Interrupt */
    if (isr & AT91C_UDP_RXRSM) {
      USB_Resume();
#if   USB_RESUME_EVENT
      USB_Resume_Event();
#endif
      pUDP->UDP_ICR = AT91C_UDP_RXRSM;
    }

    /* External Resume Interrupt */
    if (isr & AT91C_UDP_EXTRSM) {
      USB_WakeUp();
#if   USB_WAKEUP_EVENT
      USB_WakeUp_Event();
#endif
      pUDP->UDP_ICR = AT91C_UDP_EXTRSM;
    }

    /* Start of Frame Interrupt */
    if (isr & AT91C_UDP_SOFINT) {
#if USB_SOF_EVENT
      USB_SOF_Event();
#endif
      pUDP->UDP_ICR = AT91C_UDP_SOFINT;
    }

    /* Endpoint Interrupts */
    for (n = 0; n < USB_EP_NUM; n++) {
      if (isr & (1 << n)) {

        csr = pUDP->UDP_CSR[n];

        /* Setup Packet Received Interrupt */
        if (csr & AT91C_UDP_RXSETUP) {
          if (USB_P_EP[n]) {
            USB_P_EP[n](USB_EVT_SETUP);
          }
          /* Setup Flag is already cleared in USB_DirCtrlEP */
          /* pUDP->UDP_CSR[n] &= ~AT91C_UDP_RXSETUP; */
        }

        /* Data Packet Received Interrupt */
        bkm = RX_DATA_BK[RxDataBank[n]];
        if (csr & bkm) {
          if (USB_P_EP[n]) {
            USB_P_EP[n](USB_EVT_OUT);
          }
          pUDP->UDP_CSR[n] &= ~bkm;
          if (DualBankEP & (1 << n)) {
            RxDataBank[n] ^= 1;
          }
        }

        /* Data Packet Sent Interrupt */
        if (csr & AT91C_UDP_TXCOMP) {
//          pUDP->UDP_CSR[n] &= ~AT91C_UDP_TXCOMP;
          if (TxDataBank[n]) {
            pUDP->UDP_CSR[n] |= AT91C_UDP_TXPKTRDY;
            TxDataBank[n] = 0;
          }
          if (USB_P_EP[n]) {
            USB_P_EP[n](USB_EVT_IN);
          }
          pUDP->UDP_CSR[n] &= ~AT91C_UDP_TXCOMP;
        }

        /* STALL Packet Sent Interrupt */
        if (csr & AT91C_UDP_STALLSENT) {
          if ((csr & AT91C_UDP_EPTYPE) == AT91C_UDP_EPTYPE_CTRL) {
            if (USB_P_EP[n]) {
              USB_P_EP[n](USB_EVT_IN_STALL);
/*            USB_P_EP[n](USB_EVT_OUT_STALL); */
            }
          }
          pUDP->UDP_CSR[n] &= ~AT91C_UDP_STALLSENT;
        }

      }
    }

  }

  *AT91C_AIC_EOICR = 0;                     /* End of Interrupt */
}


А вот Reset
Код
void USB_Reset (void) {
  DWORD n;

  /* Global USB Reset */
  pUDP->UDP_GLBSTATE &= ~(AT91C_UDP_FADDEN | AT91C_UDP_CONFG | AT91C_UDP_RMWUPE);
  pUDP->UDP_FADDR     =  AT91C_UDP_FEN;
  pUDP->UDP_ICR       =  0xFFFFFFFF;

  /* Reset & Disable USB Endpoints */
  for (n = 0; n < USB_EP_NUM; n++) {
    pUDP->UDP_CSR[n] = 0;
    RxDataBank[n] = 0;
    TxDataBank[n] = 0;
  }
  pUDP->UDP_RSTEP = 0xFFFFFFFF;
  pUDP->UDP_RSTEP = 0;

  /* Setup USB Interrupts */
  pUDP->UDP_IER = AT91C_UDP_RXSUSP | AT91C_UDP_RXRSM | AT91C_UDP_EXTRSM |
                  AT91C_UDP_SOFINT | (2^USB_EP_NUM - 1);

  /* Setup Control Endpoint 0 */
  pUDP->UDP_CSR[0] = AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL;
}


Менять их местами смысла не вижу pUDP->UDP_ICR очищает флаги прерываий. Но попробую.
Sanya_kv
Нашел другое решение, если кому интересно. Не очень красивое, но всё таки. Если в течении 1 секунды нет обмена по USB произвожу USB_Reset();
Вроде работает. Но винда заново переподключает устройство, занимает 3-5 сек.
singlskv
Цитата(Sanya_kv @ Jun 17 2009, 15:21) *
Код
  while (isr = pUDP->UDP_ISR) {
я вот не до конца уверен в правильности висения в прерывании по такому принципу,
те пока не обработаем все полученные и все вновь пришедшие прерывания...

Нужно посмотреть еще на Вашу функцию записи, там можно случайно зациклиться...
Sanya_kv
Цитата(singlskv @ Jun 18 2009, 01:52) *
Нужно посмотреть еще на Вашу функцию записи, там можно случайно зациклиться...

Пример взят стандартный из c:\Keil\ARM\Boards\Atmel\AT91SAM7S-EK\USB\HID\ можите побалываться с ним. Устройство вылетает при интенсивном обмене, примерно 10 посылок в секунду. Опрос HID = 35млСек .
В Иар сделано по другому:
Код
    status = AT91C_BASE_UDP->UDP_ISR;
    status &= AT91C_BASE_UDP->UDP_IMR;
    ...
     if (status == AT91C_UDP_RXSUSP) {
    ...
singlskv
Цитата(Sanya_kv @ Jun 18 2009, 10:28) *
Пример взят стандартный из c:\Keil\ARM\Boards\Atmel\AT91SAM7S-EK\USB\HID\ можите побалываться с ним.
у меня не Keil, поэтому взять его неоткуда, да и незачем...
Цитата
Устройство вылетает при интенсивном обмене, примерно 10 посылок в секунду. Опрос HID = 35млСек .
Ну это разьве интенсивно ? Нагрузите обменом по максимуму,
тогда ошибки будут чаще и их проще будет ловить.
Цитата
В Иар сделано по другому:
Код
    status = AT91C_BASE_UDP->UDP_ISR;
    status &= AT91C_BASE_UDP->UDP_IMR;
    ...
     if (status == AT91C_UDP_RXSUSP) {
    ...

ИМХО, это правильнее
Sanya_kv
Цитата(singlskv @ Jun 18 2009, 17:46) *
Ну это разьве интенсивно ? Нагрузите обменом по максимуму,
тогда ошибки будут чаще и их проще будет ловить.

Windows быстрее не успевает.
Код
    status = AT91C_BASE_UDP->UDP_ISR;
    status &= AT91C_BASE_UDP->UDP_IMR;
    ...
     if (status == AT91C_UDP_RXSUSP) {
    ...
не помагло. Скорей всего дело в обработке. Буду тестировать в IAR.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.