Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Контроллер повисает после перезапуска приложения, если при этом происходила передача данных по USB от контроллера приложению
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Bulat
Девайс принимает данные по некому протоколу, преобразует их в нужный формат и передает по USB на ПК. Если прекратить передавать по этому протоколу данные девайсу, а затем закрыть приложение на ПК, то при следующем запуске приложения девайс нормально определяется и работает. Но, если во время приема девайсом данных и, соответственно, передачей их по USB на ПК выйти из приложения, то девайс повисает и при следующем запуске приложения уже не определяется. Приходится передергивать USB-кабель девайса и еще раз перезапускать приложение. Только после этого девайс начинает работать. Получается в FIFO UDP девайса остаются непрочитанные приложением данные. При закрытии приложения девайсу посылается команда Turn off. Чтобы очистить FIFO использовал сброс конечной точки по команде Turn off:
Код
AT91C_BASE_UDP->UDP_RSTEP |= AT91C_UDP_EPINT1;
AT91C_BASE_UDP->UDP_RSTEP &= ~(AT91C_UDP_EPINT1);

... не помогает.
По этой же команде Turn off пробовал производить программный сброс процессора и периферии 2-мя способами:
1.
Код
((void (*)())0x0000)();

2.
Код
#define AT91C_RSTC_KEY_MY        ((unsigned int) 0xA5 << 24) // (RSTC) Password
            AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_KEY_MY | AT91C_RSTC_PROCRST | AT91C_RSTC_PERRST;

... тоже не помогло.
Какие еще возможны решения этой проблемы?
Заранее благодарен!
aaarrr
Цитата(Bulat @ Jun 24 2010, 15:30) *
При закрытии приложения девайсу посылается команда Turn off.

А контроллер ее точно принимает и обрабатывает, или зависает еще раньше, потому что его перестали читать?
Bulat
Цитата(aaarrr @ Jun 24 2010, 17:43) *
А контроллер ее точно принимает и обрабатывает, или зависает еще раньше, потому что его перестали читать?

Точно принимает, потому что, если его даже перестанут читать, он не зависнет. Опрос битов TXCOMP и TXPKTRDY происходит в основном цикле программы (без прерываний от ендпоинтов и ожиданий TXCOMP), то есть если даже эти биты не выставлены, то контроллер продолжает работать дальше и опрашивает ендпоинт с входящими данными, среди которых и приходит Turn off.
aaarrr
Цитата(Bulat @ Jun 24 2010, 15:55) *
Точно принимает, потому что, если его даже перестанут читать, он не зависнет.

А из первого сообщения картина складывается противоположная:
Цитата
если во время приема девайсом данных и, соответственно, передачей их по USB на ПК выйти из приложения, то девайс повисает



Попробуйте описать ситуацию более подробно: как происходит "определение" устройства в программе, что именно зависает - обмен по USB, или процессор в неопределенной точке программы.
Bulat
Цитата(aaarrr @ Jun 24 2010, 18:06) *
А из первого сообщения картина складывается противоположная:
Цитата

если во время приема девайсом данных и, соответственно, передачей их по USB на ПК выйти из приложения, то девайс повисает


При выходе из приложения девайсу по USB посылается команда Turn off. Он ее никак не избежит. Я проверял, команда выполняется.

Цитата(aaarrr @ Jun 24 2010, 18:06) *
Попробуйте описать ситуацию более подробно: как происходит "определение" устройства в программе, что именно зависает - обмен по USB, или процессор в неопределенной точке программы.

Устройство в приложении открывается стандартно по Guid с помощью API функций.
Вот скелет основного цикла прошивки:
CODE

_ramfunc int main(void)
{
AT91F_USB_Open(); // CDC
USB_init();
PIO_ini();
AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1 << AT91C_ID_PIOA ) ;
Receiver_ini();
AT91F_SSC_Conf ();

//Основной цикл программы
while(1)
{
if(recA_1) //если есть данные для передачи по USB
{
if(!(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY))
{
//Заполнение FIFO UDP
unsigned int rec = recA_1;
regUDP->UDP_FDR[AT91C_EP_IN] = 11;
regUDP->UDP_FDR[AT91C_EP_IN] = rec&0xff;
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++;

}//if(!(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY))
recA_1 = 0;

//Если в буфер FIFO записано 12 слов по 5 байт = 60 байт, то отправляем
if(kA==12) { regUDP->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY; kA=0;}

}//if(recA_1)

if(length == 0) //Если буфер, принятых по USB даных пуст
{
if((AT91C_BASE_UDP->UDP_ISR) & AT91C_UDP_EPINT2) //в буфере EP2 новые данные
{
if(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & pCDC.currentRcvBank)
{
AT91F_disable_interrupt();
length = regUDP->UDP_CSR[AT91C_EP_OUT]>>16; //Считываем размер принятых по USB данных
AT91F_enable_interrupt();
}

}//if((AT91C_BASE_UDP->UDP_ISR) & AT91C_UDP_EPINT2)
}

if(length != 0) //если буфер принятых по USB данных не пуст
{
if(jj==0)
{
unsigned int com = regUDP->UDP_FDR[AT91C_EP_OUT]; //считываем команду
switch(com)
{
case 0x1 : {Turn_off(); break;}
case 0x2 : {Turn_on(); break;}
case 0x5 : {Reset(); break;}
...
default: {length--;}
}//switch

}//if(jj == 0)


if(length == 0)
{
AT91F_disable_interrupt();
Udp_ep_clr_flag(regUDP,AT91C_EP_OUT, pCDC.currentRcvBank);
if(pCDC.currentRcvBank == AT91C_UDP_RX_DATA_BK0)pCDC.currentRcvBank = AT91C_UDP_RX_DATA_BK1;
else pCDC.currentRcvBank = AT91C_UDP_RX_DATA_BK0;
AT91C_BASE_UDP->UDP_ICR = 0xFFFFFFFF;
AT91F_enable_interrupt();
}
}// if(length != 0)

if(regUDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)
{
AT91F_disable_interrupt();
regUDP->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP);
AT91F_enable_interrupt();
}

}//while(1)
}//main


По идее, по команде Turn off нужно сделать полный сброс процессора и периферии, но после этого контроллер не определяется приложением при повторном запуске. В приложении при закрытии все потоки завершаются и все хендлы закрываются.
Такая ситуация возникает только в ситуации, когда буфер FIFO UDP не пуст. Видимо контроллер повисает во время работы модуля UDP, когда то передает данные на шину. Потому что где он может зависнуть в прошивке я не вижу.
aaarrr
Цитата(Bulat @ Jun 24 2010, 16:46) *
По идее, по команде Turn off нужно сделать полный сброс процессора и периферии, но после этого контроллер не определяется приложением при повторном запуске.

Еще раз: какой механизм используется для "определения"? Почему его может сломать не пустой буфер UDP?
Выполняется ли отключение pull-up резистора на D+ при перезапуске контроллера?
Bulat
Цитата(aaarrr @ Jun 24 2010, 19:11) *
Еще раз: какой механизм используется для "определения"? Почему его может сломать не пустой буфер UDP?

Вы имеете в виду как открывается девайс в приложении? Вот код
CODE

HDEVINFO hDevInfo;
GUID Nguid = {0xCCC207C0, 0x8CBD, 0x437A, { 0x97, 0xD1, 0xB5, 0x14, 0xF3, 0x50, 0x40, 0x40 } };
GUID *guid = &Nguid;
hDevInfo = SetupDiGetClassDevs (guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
PSP_DEVICE_INTERFACE_DATA devInfoData = (PSP_DEVICE_INTERFACE_DATA)malloc(sizeof(SP_DEVICE_INTERFACE_DATA));
devInfoData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
BOOL en = 0;
while(en == 0 ) en = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, 0, devInfoData);
SetupDiGetDeviceInterfaceDetail(hDevInfo, devInfoData, NULL, 0, &requiredlength, NULL);
PSP_DEVICE_INTERFACE_DETAIL_DATA DevInfoDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredlength);
DevInfoDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SetupDiGetInterfaceDeviceDetail (hDevInfo, devInfoData, DevInfoDetail, requiredlength, &requiredlength, NULL);

TCHAR devNameOut[MAX_PATH];
strcpy( devNameOut, DevInfoDetail->DevicePath );
strcat( devNameOut, _T( "\\PIPE01" ) );
TCHAR devNameIn[MAX_PATH];
strcpy( devNameIn, DevInfoDetail->DevicePath );
strcat( devNameIn, _T( "\\PIPE00" ) );

PipeOut = CreateFile(devNameOut,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
NULL,//FILE_FLAG_OVERLAPPED,
NULL);

PipeIn = CreateFile(devNameIn,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
NULL,//FILE_FLAG_OVERLAPPED,
NULL);

Цитата(aaarrr @ Jun 24 2010, 19:11) *
Выполняется ли отключение pull-up резистора на D+ при перезапуске контроллера?

По команде Turn off, когда я пытаюсь сделать программный сброс? Нет, в этом случае отключение pull-up резистора не происходит.
aaarrr
Цитата(Bulat @ Jun 24 2010, 17:23) *
Вы имеете в виду как открывается девайс в приложении?

Я имею в виду механизм. На основании чего программа решает, что устройство не функционирует.

Цитата(Bulat @ Jun 24 2010, 17:23) *
По команде Turn off, когда я пытаюсь сделать программный сброс? Нет, в этом случае отключение pull-up резистора не происходит.

Тогда естественно ничего функционировать не будет: МК будет ждать энумерации, а со стороны хоста отключение не зафиксируется.
Bulat
Цитата(aaarrr @ Jun 24 2010, 19:40) *
Тогда естественно ничего функционировать не будет: МК будет ждать энумерации, а со стороны хоста отключение не зафиксируется.

Мой девайс принимает данные от некого источника по определенному протоколу, обрабатывает эти данные и посылает их по USB на ПК. Так вот, если выключить этот "некий источник", то после перезапуска приложения девайс нормально определяется и позволяет возобновить работу, а если не отключать этот источник и перезапустить приложение, то девайс уже нереагирует не на какие команды от приложения. Поэтому я и подумал, что в первом случае приложение считает все данные из FIFO UDP девайса и после перезапуска продолжит нормально работать с девайсом и переподключение резистора не требуется в этом случае.
aaarrr
Три раза перечитал и ничего ровным счетом не понял. Откуда получается столь парадоксальный вывод про резистор? И как именно может помешать заполненное FIFO?

Вы пытаетесь сразу "решить" проблему, тогда как на самом деле она даже еще не локализована.
Bulat
Цитата(aaarrr @ Jun 24 2010, 20:01) *
Три раза перечитал и ничего ровным счетом не понял. Откуда получается столь парадоксальный вывод про резистор? И как именно может помешать заполненное FIFO?

Вы пытаетесь сразу "решить" проблему, тогда как на самом деле она даже еще не локализована.


Нарисовал структурную схему, чтобы было наглядно (см. прикрепленный файл). Изначально S1 замкнут и данные от источника данных передаются на мое устройство, а оттуда на ПК. Если сначало разомкнуть S1, а затем закрыть приложение (не отключаю USB-кабеля), а затем опять запустить приложение, то с устройством можно продолжать работать. То есть я резистор не отключал и приложение нормально повторно открыло драйвер и возобновило прием и передачу данных по USB. Если же S1 не размыкать и перезапустить приложение, то устройство перестает реагировать на запросы приложения.
aaarrr
Сбрасывать процессор (и, соответственно, модуль UDP) без отключения резистора нельзя.
Bulat
Цитата(aaarrr @ Jun 24 2010, 20:27) *
Сбрасывать процессор (и, соответственно, модуль UDP) без отключения резистора нельзя.

а что вы посоветуете делать в моем случае, когда я не могу отключать подтягивающий резистор?
aaarrr
Для начала локализовать проблему, т.е. найти где, что, и почему именно перестает работать. Отмените любые действия (сбросы и т.п.) по "Turn off". Добавьте диагностику в программу на ПК, диагностический вывод на МК. Отлаживать неработающие программу и устройство можно бесконечно, если они умеют только сурово молчать при ошибках.
toweroff
Цитата(aaarrr @ Jun 24 2010, 19:02) *
если они умеют только сурово молчать при ошибках.

все-таки, не при ошибках, а при событиях, скорее.
Хотя... если событие не обрабатывается - это ошибка. Программера
Bulat
Проблему локализовал.
Если во время приема девайсом данных от некого источника и передачи их по USB на ПК мы перезагружаем приложение, то приложение повторно балгополучно открывает девайс и производит в него запись команд, но девайс не отвечает. Дело в том, что при перезагрузке приложения в FIFO UDP контролера остаются несчитанные данные, а при запуске приложения сначала запрашивается серийный номер девайса, но так как у нас в FIFO в этот момент неизвестно что и неизвестно какого размера, то происходит сбой - readfile считывает неизвестно что.
Поэтому я хочу при закрытии приложения, по комнаде "Turn Off" сбрасывать конечную точку IN с помощью регистра UDP_RSTEP, но перед этим необходимо послать хосту Stall и дождаться подтверждения. Привожу код команды "Turn Off":
Код
__ramfunc void Turn_off()
{
  
   AT91C_BASE_SYS->PIOA_IDR = 0xffffffff;

   //посылаем Stall хосту и ждем подтверждения
   pUdp->UDP_CSR[0] |= AT91C_UDP_FORCESTALL;
   while(!(pUdp->UDP_CSR[0] & AT91C_UDP_ISOERROR));
   pUdp->UDP_CSR[0] &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);
   while (pUdp->UDP_CSR[0] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));
  
   //Сброс конечной точки
   AT91C_BASE_UDP->UDP_RSTEP |= AT91C_UDP_EPINT1;
   AT91C_BASE_UDP->UDP_RSTEP &= ~AT91C_UDP_EPINT1;


Видимо я что-то упустил, так как в таком виде проблему решить всерано не удалось.
aaarrr
Состояние STALL Bulk-точки нельзя снимать просто так в произвольный момент времени, это должен делать хост командой Clear Feature. Выполнять сброс точки следует именно по этой команде.

Цитата(Bulat @ Jun 25 2010, 12:55) *
Видимо я что-то упустил, так как в таком виде проблему решить всерано не удалось.

Т.е. при считывании серийного номера readfile все равно возвращает мусор?
Bulat
Цитата(aaarrr @ Jun 25 2010, 15:14) *
Состояние STALL Bulk-точки нельзя снимать просто так в произвольный момент времени, это должен делать хост командой Clear Feature. Выполнять сброс точки следует именно по этой команде.

Тогда когда мне делать сброс конечной точки. Какой-то флаг ждать?

Цитата(aaarrr @ Jun 25 2010, 15:14) *
Т.е. при считывании серийного номера readfile все равно возвращает мусор?

ReadFile(PipeIn, &buf_r, 3, &RealRead, NULL);
То есть, считываю 3 байта, RealRead = 0 и в buf_r мусор.
aaarrr
Цитата(Bulat @ Jun 25 2010, 13:24) *
Тогда когда мне делать сброс конечной точки. Какой-то флаг ждать?

Ждать запрос CLEAR_FEATURE->HALT для нужной точки. Драйвер, возможно, нужно попросить это сделать.

Цитата(Bulat @ Jun 25 2010, 13:24) *
ReadFile(PipeIn, &buf_r, 3, &RealRead, NULL);
То есть, считываю 3 байта, RealRead = 0 и в buf_r мусор.

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