Есть проект, на стадии конечной отладки. Все вроде проверено, оттестировано и работает. Но вот после очередной версии FW от тестеров стали приходить жалобы - платы самопроизвольно перезагружаются.
Разбор полетов и воспроизведение условий показало, что проблема в следующем :
Включение watchdog в прошивке приводит к тому, что под воздействием "DOS-атаки" UDP пакетами по ethernet плата через некоторое время (10-50 секунд) после старта перегружается по WD.
Atmel AT91SAM7X, PHY : RTL8201BL, micrium OS ( OS_VERSION = 283u ), IAR 4.41
tcp/ip стек от микриума.
Работа с WD организована следующим образом - в системном обработчике IdleTaskHook (Idle task имеет самый низкий приоритет) проверяется время, прошедшее с предыдущего сброса WD таймера. Если прошло более половины периода WD, он сбрасывается.
Код :
Код
void WD_Init( unsigned short period, unsigned char createTimer )
{
// enable clock
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SYS);
if (!period)
{
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
return;
}
// first, creating OS timer
if (createTimer)
{
unsigned char err;
OS_TMR * WDTimer = OSTmrCreate(period / 3, period / 3, OS_TMR_OPT_PERIODIC, (OS_TMR_CALLBACK)WD_TimerCallback, 0, "Watchdog timer", &err );
if ( (!period) || (err != OS_NO_ERR) || (!OSTmrStart( WDTimer, &err)) || (err != OS_NO_ERR) )
{
// disabling WD, we can't start timer
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
return;
}
}
// timer started, configure WD
// AT91C_BASE_WDTC->WDTC_WDCR
__wd_period = period / 2;
__wd_timestamp = OSTimeGet();
period = period / 4; // 4 msec per WD tick
period = (period & 0x0FFF); // cut to 12 bit
//AT91C_BASE_WDTC->WDTC_WDMR = ( AT91C_WDTC_WDDBGHLT | AT91C_WDTC_WDIDLEHLT | AT91C_WDTC_WDRSTEN | AT91C_WDTC_WDRPROC | (( period / 4 * 3) << 16) | (period) );
AT91C_BASE_WDTC->WDTC_WDMR = ( AT91C_WDTC_WDDBGHLT | AT91C_WDTC_WDIDLEHLT | AT91C_WDTC_WDFIEN | (( period / 4 * 3) << 16) | (period) );
// register IRQ handler
BSP_Set_WDIRQHandler( __WD_IRQ_Handler );
}
Процедура, которая сбрасывает таймер :
Код
void WD_Tick( void )
{
if (!__wd_period)
return;
if ( (OSTime - __wd_timestamp) > __wd_period)
{
AT91C_BASE_WDTC->WDTC_WDCR = 0xA5000001;
__wd_timestamp = OSTime;
}
}
{
if (!__wd_period)
return;
if ( (OSTime - __wd_timestamp) > __wd_period)
{
AT91C_BASE_WDTC->WDTC_WDCR = 0xA5000001;
__wd_timestamp = OSTime;
}
}
Происходит интересная вещь - на каком-то этапе перестает работать AIC. Прерывания генерируются, но системный обработчик не запускается (используется protected mode), срабатывает он только от Watchdog.
зы. Грешил на приоритеты прерываний (думал, зависаю где-то в обработчике) - но только отключение собаки решило проблему.
Буду признателен
