Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: sam9xe256 проблема с USB
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
taoga
Здравствуйте!

После включения d-cache перестали передаваться пакеты длиной больше 64 байт (не работает "ping-pong endpoint"). Для работы с USB использую код из проекта (примеров) для sam7, код в архиве.

Нажмите для просмотра прикрепленного файла

Комментарий к const_flash.c: В SRAM выделена некэшируемая область под буферы PDC SPI, для чего добавлена "грубая" таблица трансляции второго уровня. Таблицы хранятся во встроенной флэш.

CODE
//*----------------------------------------------------------------------------
//* \fn AT91F_CDC_Write
//* \brief Send through endpoint 2
//*----------------------------------------------------------------------------
static uint AT91F_UDP_Write(AT91PS_CDC pCdc, const char *pData, uint length)
{
uint cpt = 0;

while ( (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) );

// Send the first packet
cpt = MIN(length, AT91C_EP_IN_SIZE);
length -= cpt;
while (cpt--) AT91C_BASE_UDP->UDP_FDR[AT91C_EP_IN] = *pData++;
SET_CSR(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);

while (length) {
// Fill the second bank
cpt = MIN(length, AT91C_EP_IN_SIZE);
length -= cpt;
while (cpt--) AT91C_BASE_UDP->UDP_FDR[AT91C_EP_IN] = *pData++;
// Enable interrupt on endpoint
AT91C_BASE_UDP->UDP_IER = 1 << AT91C_EP_IN;
// Wait for the the first bank to be sent
while ( !(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)
&& (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) )
if ( !AT91F_UDP_IsConfigured(pCdc) ) return length;

CLEAR_CSR(AT91C_EP_IN, AT91C_UDP_TXCOMP);
SET_CSR(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
}
// Wait for the end of transfer
while ( !(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)
&& (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) )
if ( !AT91F_UDP_IsConfigured(pCdc) ) return length;

CLEAR_CSR(AT91C_EP_IN, AT91C_UDP_TXCOMP);

return length;
}


Программа зацикливается после заполнения второго банка на проверке while ( !(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) ).

Со стороны ПК используется драйвер atm6124.sys.
Подскажите, как решить проблему?
aaarrr
Т.е. зацикливается после "Wait for the the first bank to be sent"? А что делается в прерывании, которое до этого было разрешено?
taoga
Цитата(aaarrr @ Jul 11 2011, 17:03) *
Т.е. зацикливается после "Wait for the the first bank to be sent"?


Да.

Цитата(aaarrr @ Jul 11 2011, 17:03) *
А что делается в прерывании, которое до этого было разрешено?

Обработчик прерывания не установлен. Прерывания не используются.
aaarrr
Хм. А что говорит сниффер, первый пакет уходит вообще?
taoga
Цитата(aaarrr @ Jul 12 2011, 02:15) *
Хм. А что говорит сниффер, первый пакет уходит вообще?

Первый пакет (64 байта) уходит. ACK на него от хоста нет.

Цитата(aaarrr @ Jul 12 2011, 02:15) *
Хм. А что говорит сниффер, первый пакет уходит вообще?

Посылаю тестовый блок данных по 256 байт с значениями счетчика 0..256.
Первый пакет из первого банка передается нормально.
В следующем испорчен первый байт, но передаются 64 байта.
Обмен прерывается, когда в одном из пакетов теряется первый байт и передаются 63 байта.
Т.к. программа в ПК принимает определенное количество байт, и если она их не примет, не запускается
следующая команда чтения данных, и после таймаута обмен прекращается.

Т.е. после заполнения первого банка FIFO и установки AT91C_UDP_TXPKTRDY, нужно каким-то образом определить готовность AT91C_BASE_UDP->UDP_FDR к приему на передачу следующих данных?

Еще дополнение: копии экрана программы перехвата пакетов. Опущены NAK пакеты.
Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
taoga
Цитата(taoga @ Jul 11 2011, 14:36) *
Здравствуйте!

После включения d-cache перестали передаваться пакеты длиной больше 64 байт (не работает "ping-pong endpoint"). Для работы с USB использую код из проекта (примеров) для sam7, код в архиве.

Отвечаю сам себе, может кому-нибудь понадобится.
При использовании ping-pong endpoint после заполнения второго банка нужно ждать пока будет установлен TXCOMP, затем установить TXPKTRDY, только после этого очистить TXCOMP.
С помощью анализатора заметил, что один буфер передался полностью без ошибок, а на следующем произошел сбой.
Поэтому переделал код так, чтобы TXPKTRDY всегда устанавливался вперед TXCOMP.
Код работает как для передачи пакетов <=64 байт, так и больших размеров:
CODE
//#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \
|AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \
|AT91C_UDP_TXCOMP
#define REG_NO_EFFECT_1_ALL 0


/// 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 = AT91C_BASE_UDP->UDP_CSR[endpoint] ; \
reg |= REG_NO_EFFECT_1_ALL; \
reg |= (flags); \
AT91C_BASE_UDP->UDP_CSR[endpoint] = reg; \
while ( (AT91C_BASE_UDP->UDP_CSR[endpoint] & (flags)) != (flags)); \
}

/// Sets the specified bit(s) in the UDP_CSR register.
/// \param endpoint The endpoint number of the CSR to process.
/// \param flags The bitmap to clear to 0.
#define CLEAR_CSR(endpoint, flags) \
{ \
volatile unsigned int reg; \
reg = AT91C_BASE_UDP->UDP_CSR[endpoint]; \
reg |= REG_NO_EFFECT_1_ALL; \
reg &= ~(flags); \
AT91C_BASE_UDP->UDP_CSR[endpoint] = reg; \
while ( (AT91C_BASE_UDP->UDP_CSR[endpoint] & (flags)) == (flags)); \
}

//*----------------------------------------------------------------------------
//* \fn AT91F_CDC_Write
//* \brief Send through endpoint 2
//*----------------------------------------------------------------------------
static uint AT91F_UDP_Write(AT91PS_CDC pCdc, const char *pData, uint length)
{
uint cpt = 0;

while ( (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) );

// Send the first packet
cpt = MIN(length, AT91C_EP_IN_SIZE);
length -= cpt;
while (cpt--) AT91C_BASE_UDP->UDP_FDR[AT91C_EP_IN] = *pData++;
SET_CSR(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
if ( AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP )
CLEAR_CSR(AT91C_EP_IN, AT91C_UDP_TXCOMP);

while (length) {
// Fill the second bank
cpt = MIN(length, AT91C_EP_IN_SIZE);
length -= cpt;
while (cpt--) AT91C_BASE_UDP->UDP_FDR[AT91C_EP_IN] = *pData++;
// Enable interrupt on endpoint
AT91C_BASE_UDP->UDP_IER = 1 << AT91C_EP_IN;
// Wait for the the first bank to be sent
while ( !(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) )
if ( !AT91F_UDP_IsConfigured(pCdc) ) return length;

SET_CSR(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
CLEAR_CSR(AT91C_EP_IN, AT91C_UDP_TXCOMP);
}

return length;
}

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.