Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: SAM7S + USART PDC + INTS
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
defunct
Столкнулся с интересной ситуацией, сообщили что девайс иногда перестает работать, с виду вроде все ОК, светодиоды мигают, а коммуникаций с Host'ом - нет, интерфейс связи UART. Начал копать, и вот что накопал:

Чип на 55Mhz, UART0 - 115200, работа с UART'ом TX через DMA, RX - посимвольно в режиме 485-го.
Заметил что иногда после сброса по WDT - USART подвисает. Подвисает так:

После старта первая посылка по DMA уходит без проблем (в терминале вижу правильные данные), но прерывание TXRDY не происходит, поэтому больше девайс ничего не шлет... Хотя флаг TXRDY в статус регистре UART'а есть! Прерываний нет от USART'а вообще никаких, ни RX ни TX, ничего.....
Другая периферия после сброса по WDT работает нормально, вчастности таймер (EDGE_TRIGGERED) тикает, I2C (LEVEL_SENSITIVE) прерывания живут, на SPI висит SD карточка обмен через DMA с прерываниями (EDGE_TRIGGERED) работает.

Подумал UART глючит, пробовал вывести из ступора повторной инициализацией - не помогло. И не удивительно, UART то по всем признакам живой...

Повторный сброс по WDT (иногда второй, иногда третий...) приводит USART в чуства... и USART после этого живет долго и счастливо.

До конца не разобрался в чем было дело, но похоже что со сбросом AIC'a через WDT что-то не чисто, на что натолкнуло значение AIC_IMR = 0xFFFFEEE3 после сброса. Следующий код, решает мою проблему с UART'ом:

Код
static __inline void hal_ClearAIC(void)
{
    AT91PS_AIC pAIC = AT91C_BASE_AIC;            
    int i;
    pAIC->AIC_IDCR = 0xFFFFFFFF;
    pAIC->AIC_EOICR = 0; // mark last int as handled
    for (i = 0; i < 32; i++)
        pAIC->AIC_SVR[ i ] = 0xDEADBEEF;
}

вызвать первым при входе в main().

Кто-нибудь сталкивался с чем-то подобным?
Genadi Zawidowski
Между прочим, в чьём-то стартапе (благополучно слямзенном мною) был такой код:

Код
    // Perform 8 IT acknoledge (write any value in EOICR)
    for (i = 0; i < 8; i++) {
        AT91C_BASE_AIC->AIC_EOICR = 0;
    }

О, это стартап из Атмеловских примеров...
defunct
Цитата(Genadi Zawidowski @ Jun 28 2010, 09:14) *
// Perform 8 IT acknoledge (write any value in EOICR)
..
О, это стартап из Атмеловских примеров...

хм.. а почему именно 8?
aaarrr
Цитата(defunct @ Jun 28 2010, 10:31) *
хм.. а почему именно 8?

По числу приоритетов.

А вот скажите, зачем используется куча edge triggered прерываний - какой-нибудь смысл в этом есть?
defunct
Цитата(aaarrr @ Jun 28 2010, 09:53) *
По числу приоритетов.

Спасибо, поставлю 8 и себе.

Цитата
А вот скажите, зачем используется куча edge triggered прерываний - какой-нибудь смысл в этом есть?

Думаю все из-за этого:
Note that it is not recommended to use the USART interrupt line in edge sensitive mode.
был напуган, и наставил везде edge-triggered. smile.gif

Насколько я понимаю вся разница между sensitive и tiggered в скорости детекта, первый быстрее на 1 цикл, а второй должен быть надежней в виду того, что по идее не должен пропускать короткие IRQn. Может неправильно понимаю?
aaarrr
Цитата(defunct @ Jun 28 2010, 10:59) *
Думаю все из-за этого:
Note that it is not recommended to use the USART interrupt line in edge sensitive mode.
был напуган, и наставил везде edge-triggered. smile.gif

Эмм... То есть сделали наоборот? smile.gif

Цитата(defunct @ Jun 28 2010, 10:59) *
Насколько я понимаю вся разница между sensitive и tiggered в скорости детекта, первый быстрее на 1 цикл, а второй должен быть надежней в виду того, что по идее не должен пропускать короткие IRQn. Может неправильно понимаю?

Короткие IRQn у внутренних источников и возникать по хорошему не должны. Но на этот случай предусмотрено spurious irq.
Зато в случае работы по фронту есть ненулевая вероятность прошляпить прерывание, если вовремя не сделать запись в ICCR
Таким образом, работа по фронту с внутренними источниками никаких преимуществ не имеет, зато имеет недостатки:
- латентность на один такт больше
- возникает необходимость дополнительного сброса
- потенциально может принести проблемы при невнимательном обращении

Последний пункт больше относится к начинающим, но именно они почему-то упорно пишут всюду EDGE_TRIGGERED sad.gif
defunct
Цитата(aaarrr @ Jun 28 2010, 12:01) *
Эмм... То есть сделали наоборот? smile.gif

Не думаю. Если SCR TYPE для UART'а поставить в LEVEL_SENSITIVE то прерывания от UART на 55Mhz глючат.
Что наводит на мысль, слово SENSITIVE в ДШ написано верно, а вот слово EDGE - нет, подозреваю что там должно было быть "not recommended to use the USART interrupt line in level sensitive mode", а не "edge sensitive".
EDGE_TRIGGERED с UART'ом работает стабильно, на любых частотах.

Для байтовых прерываний как I2C - короткая latency необходима, а для DMA'шных и прерываний системного таймера (раз в 1ms) - latency не критично, главное чтоб стабильно работали.
aaarrr
Цитата(defunct @ Jun 28 2010, 21:25) *
Если SCR TYPE для UART'а поставить в LEVEL_SENSITIVE то прерывания от UART на 55Mhz глючат.

Как именно они глючат, и какой механизм помогает избежать глюков в edge-sensetive mode?

Цитата(defunct @ Jun 28 2010, 21:25) *
Что наводит на мысль, слово SENSITIVE в ДШ написано верно, а вот слово EDGE - нет, подозреваю что там должно было быть "not recommended to use the USART interrupt line in level sensitive mode", а не "edge sensitive".

Точно такие же "ошибки" присутствуют в описаниях PWM и CAN.

P.S. В предыдущем посте я как-то упустил из виду, что edge-triggered источники снимаются автоматически при чтении IVR, так что половиной одного недостатка меньше.
defunct
Цитата(aaarrr @ Jun 29 2010, 13:03) *
Как именно они глючат,

Перестают работать абсолютно все прерывания, в т.ч. и более приоритетные.

Цитата
и какой механизм помогает избежать глюков в edge-sensetive mode?

Да ничего особенного, обычный обработчик... такой как для всего остального.
Код
void uart0_ISR(void) __irq
{
    UART_ISR( &u0 );
    *AT91C_AIC_EOICR = 0; // signal VIC to end of interrupt activity    
}


Для сравнения - I2C'шный, в level sensitive:
Код
void i2c_ISR (void)    __irq
{
    I2C_ISR();
    *AT91C_AIC_EOICR = 0; // signal VIC to end of interrupt activity
}



Сам UART_ISR вот такой:

Код
static __inline void UART_ISR( PUART_CONTROL pUART )
{
    AT91PS_USART pCOM = pUART->pCOM;
    U32 status = pCOM->US_CSR;

    if (status & AT91C_US_ENDTX )
    {
        PRING_BUF pRing = pUART->pTxRing;
        RingDMAEndOfTransfer( pRing );
        pCOM->US_IDR = AT91C_US_ENDTX; // disable Tx int
        pRing->busy = 0;
        uart_DispatchPort( pUART );  // <-- эта функция просто перезаряжает DMA если есть чем.
        pUART->NumTxInts++;
    }
    
    if ( status & AT91C_US_RXRDY)
    {
        if (pUART->rx_cb)
            pUART->rx_cb( AT91F_US_GetChar( pCOM) );
        else
        {
            AT91F_US_GetChar( pCOM); // dummy read
        }
    }

    if ( status & AT91C_US_OVRE)
    {
         AT91F_US_GetChar( pCOM ); // clear RXRDY
    }

    if ( status & AT91C_US_TIMEOUT)
    {
        pCOM->US_CR = AT91C_US_STTTO;
    }
    // Reset the status bit
    pCOM->US_CR = AT91C_US_RSTSTA;

}
aaarrr
Цитата(defunct @ Jun 29 2010, 15:45) *
Перестают работать абсолютно все прерывания, в т.ч. и более приоритетные.

Значит где-то есть (или был) капитальный глюк. Ибо механизмов, допускающих такое поведение и только в level-sensetive, не просматривается.
Один глюк вижу: запрет прерывания ENDTX никак не мешает выполняться условию (status & AT91C_US_ENDTX), т.к. на status маска IMR не накладывается.
defunct
Цитата(aaarrr @ Jun 29 2010, 15:09) *
Один глюк вижу: запрет прерывания ENDTX никак не мешает выполняться условию (status & AT91C_US_ENDTX), т.к. на status маска IMR не накладывается.

Действительно, спасибо что заметили.
Только это безобидный глюк, и он никак не мог "завалить" все прерывания.
EndOfTransfer делает следующее
Код
    pRing->head += pRing->CurrFrameSize;
    if (pRing->head >= pRing->size)
        pRing->head -= pRing->size;
    pRing->CurrFrameHead = pRing->head;
    pRing->CurrFrameSize = 0;

Если ничего не отправляли то в CurrFrameSize останется 0, а если отправляли тогда ENDTX будет неустановлен, либо разрешен.
aaarrr
Цитата(defunct @ Jun 29 2010, 16:24) *
Только это безобидный глюк, и он никак не мог "завалить" все прерывания.

Ну, этого я и не утверждал. Не безобидный надо искать. А для этого нужно как минимум знать состояние AIC, периферии, генерирующей прерывания, и ядра в момент "завала". Ибо сам термин весьма расплывчатый и ровным счетом ничего не объясняет.
defunct
Цитата(aaarrr @ Jun 29 2010, 15:33) *
Не безобидный надо искать. А для этого нужно как минимум знать состояние AIC, периферии, генерирующей прерывания, и ядра в момент "завала". Ибо сам термин весьма расплывчатый и ровным счетом ничего не объясняет.

Не буду ходить вокруг да около, у Вас UART в LEVEL_SENSITIVE включен? Если да какая частота чипа, бод рейт uart'а, приоритет прерывания и используется ли TX DMA?
Хочу попробовать, оставить один только UART и посмотреть будет ли все ОК с level sensitive.
aaarrr
Цитата(defunct @ Jun 29 2010, 16:45) *
Не буду ходить вокруг да около, у Вас UART в LEVEL_SENSITIVE включен?

Всегда и все в level-sensetive.

Цитата(defunct @ Jun 29 2010, 16:45) *
Если да какая частота чипа, бод рейт uart'а, приоритет прерывания и используется ли TX DMA?
Хочу попробовать, оставить один только UART и посмотреть будет ли все ОК с level sensitive.

В разных проектах 48 и 55МГц, PDC практически всегда используется и на прием и на передачу.
Приоритет, если используется, то обычно где-то посередине (есть еще прерывания и с большим и с меньшим приоритетом).
Каких-либо проблем не наблюдалось никогда.
SpiritDance
Цитата(defunct @ Jun 28 2010, 10:06) *
Столкнулся с интересной ситуацией, сообщили что девайс иногда перестает работать, с виду вроде все ОК, светодиоды мигают, а коммуникаций с Host'ом - нет, интерфейс связи UART. Начал копать, и вот что накопал:

До конца не разобрался в чем было дело, но похоже что со сбросом AIC'a через WDT что-то не чисто, на что натолкнуло значение AIC_IMR = 0xFFFFEEE3 после сброса. Следующий код, решает мою проблему с UART'ом:

вызвать первым при входе в main().

Кто-нибудь сталкивался с чем-то подобным?


Я сталкивался. только у меня АЦП подвисал на S256, когда я работал без DMA. Делал он это нерегулярно, причем, если подвисал то и повторные перезапуски оживить процессор не могли.

Боролся перезапуском AIC в main:
Код
  /* запрещаем все прерывания */
  AT91C_BASE_AIC->AIC_IDCR = AT91C_ALL_INT;
  
  /* устанавливаем на все ресурсы edge_triggered mode */
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_FIQ] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PIOA] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_ADC] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SPI] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_US0] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_US1] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SSC] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TWI] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PWMC] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC1] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC2] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_IRQ0] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_IRQ1] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_LOWEST;
  
  /* сбрасываем все прерывания */  
  AT91C_BASE_AIC->AIC_ICCR = AT91C_ALL_INT;
  
  AT91C_BASE_AIC->AIC_SPU = (AT91_REG)spurious_vector;


Вобщем, пришел к выводу что разработчики сделали какой-то индусский WDT или AIC, который при определенных фазах луны может подвести.

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