Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с отправкой пaкетов по UDP (AT91SAM7S)
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Bulat
Ниже приведен кусок основного цикла программы, отвечающий за формирование и отправку данных через UDP. При приеме данных на хост периодически теряются пакеты (60 байт), а то и по несколько пакетов за раз. Количество потерь возрастает, если подключать девайс к более слабой машине.
Код
while(1)
{
      if(recA_1)         //если 32-битное слово готово к отправке на хост                                                    
          {  
            if(!(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY))  //если свободен буфер UDP
            {
              unsigned int crc = 0;
              unsigned int by = recA_1;
              for(unsigned int ib=0;ib<32;ib++)  //Подсчет бита четности
              {
                crc = crc^(by&0x1);  
                by >>=1;
              }
              if(crc)
              {
              unsigned int rec = recA_1;
              regUDP->UDP_FDR[AT91C_EP_IN] = 11;        //командное слово
              regUDP->UDP_FDR[AT91C_EP_IN] = rec&0xff;    //Разбивка 32-битного передаваемого слова на байты                
              unsigned int m_stat = rec>>8;        
              regUDP->UDP_FDR[AT91C_EP_IN] = m_stat&0xff;
              m_stat = rec>>16;
              regUDP->UDP_FDR[AT91C_EP_IN] = m_stat&0xff;
              m_stat = rec>>24;
              regUDP->UDP_FDR[AT91C_EP_IN] = m_stat&0xff;
              kA--;  // счетчик записанных слов в FIFO UDP
              }// if(rcrc1)
            }
            recA_1 = 0;
            
            if(kA==0)  //Если FIFO заполнен (12 слов по 5 байт, 60 байт)
            {
              regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
              regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);            
              kA=12;
            }  
          }

}//while(1)


Почему потеря при приеме хостом идет пакетами? Как пользоваться 2-мя банками при передачи на хост?
aaarrr
Цитата(Bulat @ Mar 25 2010, 12:56) *
Почему потеря при приеме хостом идет пакетами?

Так делать нельзя:
Код
  regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
  regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);

Почитайте правила доступа к CSR в DS.

Цитата(Bulat @ Mar 25 2010, 12:56) *
Как пользоваться 2-мя банками при передачи на хост?

1. Загружаем в FIFO самый первый пакет, ставим TXPKTRDY, переходим к п.2
2. Загружаем в FIFO следующий пакет, переходим к п.3
3. Ждем установки TXCOMP, ставим TXPKTRDY, снимаем TXCOMP, переходим к п.2
Bulat
Цитата(aaarrr @ Mar 25 2010, 15:11) *
Так делать нельзя:
Код
  regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
  regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);

Почитайте правила доступа к CSR в DS.


1. Загружаем в FIFO самый первый пакет, ставим TXPKTRDY, переходим к п.2
2. Загружаем в FIFO следующий пакет, переходим к п.3
3. Ждем установки TXCOMP, ставим TXPKTRDY, снимаем TXCOMP, переходим к п.2


а вот так правильно будет сделать?
Код
while(1)
{
       if(recA_1)                                                              
          {  
            if(!(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY))
            {
              regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);
              
              ...

              kA--;

            }
                        
            if(kA==0)
            {
              regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;      
              kA=12;
            }  
          }
}//while(1)
aaarrr
Нет.
Bulat
Цитата(aaarrr @ Mar 25 2010, 17:26) *
Нет.

надо ожидать TXCOMP, только потом повторную запись производить?
aaarrr
Цитата(Bulat @ Mar 25 2010, 15:44) *
надо ожидать TXCOMP, только потом повторную запись производить?

Да. И TXCOMP можно снимать только после установки TXPKTRDY.
Bulat
Цитата(aaarrr @ Mar 25 2010, 18:36) *
Да. И TXCOMP можно снимать только после установки TXPKTRDY.

Я не могу зависать программу на ожидании TXCOMP, поэтому я сделал следующим образом
Код
while(1)                                    // MAIN infinite LOOP
{        
        
       if(f_wr_b0 == 1) //первая запись в банк
       {
            if(!(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY))
            {
              ...
              //заполнение буфера
              ...
              kA--;              
            }
            
            if(kA==0)
            {
              regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
              kA=12;
              f_wr_b0 = 0;
            }
        }//if(f_wr_b0 == 1)

        else //последующие записи в банк
        {
            if(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)
            {
              regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);
              
              ...
              //заполнение буфера
              ...
              kA--;    
            }
            
            if(kA==0)
            {
              regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
              kA=12;
            }
        }  
      
}//while(1)

но так вообще перестала работать...
aaarrr
Цитата(Bulat @ Mar 25 2010, 18:05) *
Я не могу зависать программу на ожидании TXCOMP...

Придется смочь.
Bulat
Цитата(aaarrr @ Mar 25 2010, 20:44) *
Придется смочь.

Я попытался через 2 банка передавать данные на хост
CODE

while(1) // MAIN infinite LOOP
{
if(bank == 0)
{
if(!(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY))
{
//заполняем первый банк
...
}

if(kA==0)
{
bank = 1;
regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
kA=12;
}

}

else //if(bank = 1)
{
if(chTXC == 0) //второй банк не заполнен
{
//заполняем второй банк
...
if(kA==0) chTXC = 1;

}

else //второй банк заполнен
{
if(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)
{
chTXC = 0;
regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);
kA = 12;
}
}//else chTXC == 1

}//else if(bank = 1)
}

То есть тут я не задерживаю выполнение основного цикла программы на ожидании TXCOMP, а просто периодически опрашиваю его в основном цикле. Но так нестабильно работает. Бывает нормально, стабильно передает данные по USB, а бывает почти сразу захлебывается и перестает передавать. И всеравно пропусков много.
aaarrr
Еще раз: так -
Код
    regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
    regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);

делать нельзя! Почитайте наконец даташит.
Bulat
Вы писали
Цитата(aaarrr @ Mar 25 2010, 15:11)
3. Ждем установки TXCOMP, ставим TXPKTRDY, снимаем TXCOMP, переходим к п.2

CODE

if(bank == 0)
{

if(!(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY))
{
//запись в FIFO 5 байт
kA--;
}

if(kA==0)
{
bank = 1;
regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
kA=12;
}

}//if(bank == 0)

else //if(bank = 1)
{
//if(chTXC == 0) //bank 1 åùå íå çàïîëíåí

//запись в FIFO 5 байт
kA--;

if(kA==0)
{
//chTXC = 1;
while(!(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP));
regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);
kA = 12;
}

}//else if(bank = 1)

В соответствии с тем, что вы писали и что в документации, после записи во второй банк ожидаю TXCOMP, устанавливаю TXPKTRDY и сбрасываю TXCOMP
Код
  while(!(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP));                      
                       regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
                       regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);
aaarrr
Еще раз читаем документацию:
Цитата
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.

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