реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Проблема с отправкой пaкетов по UDP (AT91SAM7S), наблюдаются пропуски пакетов при приеме
Bulat
сообщение Mar 25 2010, 09:56
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Ниже приведен кусок основного цикла программы, отвечающий за формирование и отправку данных через 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-мя банками при передачи на хост?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 25 2010, 10:11
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(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
Go to the top of the page
 
+Quote Post
Bulat
сообщение Mar 25 2010, 10:58
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Цитата(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)
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 25 2010, 12:26
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Нет.
Go to the top of the page
 
+Quote Post
Bulat
сообщение Mar 25 2010, 12:44
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Цитата(aaarrr @ Mar 25 2010, 17:26) *
Нет.

надо ожидать TXCOMP, только потом повторную запись производить?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 25 2010, 13:36
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



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

Да. И TXCOMP можно снимать только после установки TXPKTRDY.
Go to the top of the page
 
+Quote Post
Bulat
сообщение Mar 25 2010, 15:05
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Цитата(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)

но так вообще перестала работать...
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 25 2010, 15:44
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



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

Придется смочь.
Go to the top of the page
 
+Quote Post
Bulat
сообщение Mar 25 2010, 18:03
Сообщение #9


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Цитата(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, а бывает почти сразу захлебывается и перестает передавать. И всеравно пропусков много.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 25 2010, 19:05
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Еще раз: так -
Код
    regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY;
    regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);

делать нельзя! Почитайте наконец даташит.
Go to the top of the page
 
+Quote Post
Bulat
сообщение Mar 30 2010, 05:45
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Вы писали
Цитата(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);
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 30 2010, 08:39
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Еще раз читаем документацию:
Цитата
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 нужно запрещать прерывания.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 20:34
Рейтинг@Mail.ru


Страница сгенерированна за 0.01485 секунд с 7
ELECTRONIX ©2004-2016