Перейти к содержанию
    

Интересное поведение EMAC на LPC17xx

Очень занятное поведение флага INTSTATUS_bit.RXDONEINT обнаружилось.

 

Разрешено только прерывания RXDONEINT. Там такой код:

void Ethernet_IRQHandler(void)
{
  UREG i='0';
  do
  {
    INTCLEAR=1UL<<3; //RxDoneInt
    i++;
  }
  while(INTSTATUS_bit.RXDONEINT);
  usart0_txc(i);
  NVIC_ClrPend(NVIC_ETHR);
  NVIC_SetPend(NVIC_RIT); //Ñòàðòóåì RIT_IRQHandler
}

 

Неспеша кормлю девайсу по одному пакету (дабы быть уверенным, что никакого переполнения не происходит). В результате в консоль сыпется:

 

122212112121121112122222222112112211212222222121111....

 

Пуристы для тестов могут заменить usart0_txc на ногодрыг и наблюдать осциллографом тот же результат - импульсов то 1, то 2.

 

Если бы просто сделать

void Ethernet_IRQHandler(void)
{
  INTCLEAR=1UL<<3; //RxDoneInt
  NVIC_ClrPend(NVIC_ETHR);
  NVIC_SetPend(NVIC_RIT); //Ñòàðòóåì RIT_IRQHandler
}

то этот код часто (а то и вообще всегда) вызывается 2 раза - не сбрасывается флаг RxDoneInt, соответственно, сброс соответствующего бита в NVIC не помогает - не снят изначальный флаг, т.е. происходит опять поднятие флага в NVIC и последующее прерывание. Правда, на второй заход сброс таки происходит.

 

Вот такой код вроде (ну ибо на обозримом отрезке времени мне не удалось наблюдать двойной вызов) всегда вызывается один раз:

void Ethernet_IRQHandler(void)
{
  INTSTATUS;
  __no_operation();
  __no_operation();
  __no_operation();
  __no_operation();
  __no_operation();
  __no_operation();
  INTCLEAR=1UL<<3;//RxDoneInt
  NVIC_ClrPend(NVIC_ETHR);
  NVIC_SetPend(NVIC_RIT); //Ñòàðòóåì RIT_IRQHandler
}

 

Ересь какая-то в общем. Другие биты не проверял.

 

Есть у кого какие мысли?

 

В общем-то такое поведение и не особо страшно, но уж очень стремно :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Очень занятное поведение флага INTSTATUS_bit.RXDONEINT обнаружилось.

Мне кажется что у него какой-то внутренний сигнал, устанавливающий запрос RXDONEINT не успевает сняться.

Если быстро заходите в прерывание и пытаетесь сбросить запрос, то внутренний "триггер" (не флип-флоп, а именно спусковой крючок) снова его ставит. А если немножко подождать - то внутренний "триггер" успевает сняться и все OK.

У меня в прерывании с регистрами EMAC ничего не делается - просто ставится событие RTOS, поэтому до обработки собственно запроса в приоритетном потоке проходит некоторое время (явно больше чем Ваши NOPы), и такого поведения не наблюдается.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне кажется что у него какой-то внутренний сигнал, устанавливающий запрос RXDONEINT не успевает сняться.

 

Да вот там есть интересная фраза такая в мане, что

Note that all bits are flip-flops with an asynchronous set in order to be able to generate interrupts if there are wake-up events while clocks are disabled.

 

Какими они там сигналами асинхронно выставляются, я уж хз. Запросто эти сигналы могут быть заведены на вход S триггеров и быть по длительности хз какими. Вот и не сбрасывается.

 

У меня в прерывании с регистрами EMAC ничего не делается - просто ставится событие RTOS

 

Так тут тоже самое. NVIC_SetPend(NVIC_RIT) - это и есть запуск потока обработки. Только у него приоритет ниже, посему начинает обрабатывать позже.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Разрешено только прерывания RXDONEINT. Там такой код:

Я правильно понял - происходит двойной заход в обработчик?

По моему NVIC должен запрещать двойные заходы. Только после полного выхода.

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

while(INTSTATUS_bit.RXDONEINT);

Посмотрите соответствующий код в ассемблере, нет ли там записи в INTSTATUS.

У меня были какие-то неприятности с прерываниями от ЕМАС, когда я делал так:

if (LPC_EMAC->IntStatus & (1 << INT_RX_DONE))

давненько было - не помню подробностей.

Сделал так:

unsigned int temp = LPC_EMAC->IntStatus;
if (temp & INT_RX_DONE)
{
  LPC_EMAC->IntClear = INT_RX_DONE;
}

И неприятностей больше не было.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если dsb вставить после записи INTCLEAR?

 

Барьеры не помогают (только как задержка вместо нопов). Я тоже сразу подумал о синхронизации всяких Load-Store конвейеров, но это не оно.

 

Я правильно понял - происходит двойной заход в обработчик?

 

Не двойной заход. Вход-выход и опять вход-выход. На втором входе все замечательно очищается.

 

void Ethernet_IRQHandler(void)
{
  INTCLEAR=1UL<<3;//RxDoneInt
  NVIC_ClrPend(NVIC_ETHR);
  ...тут например дрыгаем ножкой для теста
}

 

Такой код дрыгает ножкой два раза на один пакет. Без паузы.

 

Посмотрите соответствующий код в ассемблере, нет ли там записи в INTSTATUS.

 

Конечно нет. Код корректный.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так тут тоже самое. NVIC_SetPend(NVIC_RIT) - это и есть запуск потока обработки. Только у него приоритет ниже, посему начинает обрабатывать позже.

Не совсем то же самое - Вы цупите INTCLEAR. Я прерывания от EMAC запрещаю через NVIC:

void 
lw_lpc17_emac_handler(
    void)
{
    tn_event_iset(&glw_lpc17_netif->event, MACEVT_MACIRQ);
    NVIC_IDCR0 = (1<<IRQ_EMAC);
}

Разбор чего там EMAC захотел и общение с его регистрами происходит позже в потоке

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не совсем то же самое - Вы цупите INTCLEAR. Я прерывания от EMAC запрещаю через NVIC:

 

Ну тогда похоже Вы не видите этих граблей, ибо очень долго до собственно сброса флага.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void Ethernet_IRQHandler(void)
{
  UREG i='0';
  do
  {
    INTCLEAR=1UL<<3; //RxDoneInt
    i++;
  }
  while(INTSTATUS_bit.RXDONEINT);
  usart0_txc(i);
  NVIC_ClrPend(NVIC_ETHR);
  NVIC_SetPend(NVIC_RIT); //Ñòàðòóåì RIT_IRQHandler
}

 

void Ethernet_IRQHandler(void)
{
  INTSTATUS;
  __no_operation();
  __no_operation();
  __no_operation();
  __no_operation();
  __no_operation();
  __no_operation();
  INTCLEAR=1UL<<3;//RxDoneInt
  NVIC_ClrPend(NVIC_ETHR);
  NVIC_SetPend(NVIC_RIT); //Ñòàðòóåì RIT_IRQHandler
}

 

Я с EMAC плотно пока не работал, поэтому есть лишь догадка: в первом случае INTSTATUS вычитывается ПОСЛЕ первого обнуления в INTCLEAR, а во втором СНАЧАЛА читается статус, потом очищается прерывание. Может быть тот самый упомянутый выше "спусковой крючок" находится в INTSTATUS и сначала надо его прочитать (как в некоторых self-clear прерываниях), а потом уже принудительно прописать бит в INTCLEAR?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я в LPC1768 не смог победить их работу с прерыванием RxDone. По итогу сделал поллинг индекса в DMA. В других примерах (FreeRTOS например), сделано так же. Прерывание там используется только чтобы проснуться. Да, а заметили, что первые пара пакетов шлётся криво? В Errata описан такой баг.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

поэтому есть лишь догадка

 

Я так тоже думал. Нет, просто паузы достаточно для последующей нормальной очистки флага.

 

Я в LPC1768 не смог победить их работу с прерыванием RxDone.

 

А что его побеждать? Оно работает.

 

Да, а заметили, что первые пара пакетов шлётся криво? В Errata описан такой баг.

 

Хватило квалификации не наступить. Ибо изначально изучил Errata и закодил передачу пары пакетов заранее. И вообще, описанный баг превращается в фичу ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А что его побеждать? Оно работает.

А у меня не работает. Киньте что ли сюда код обработки прерывания - уберу у себя поллинг.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Люди, а каких вы скоростей на Lpc17 достигаете по tcp?

 

Смотря какую полезную нагрузку вкладывать. В принципе, при верном подходе утилизируется вся доступная полоса.

 

Да, кстати, собственно по теме топика. Оказывается, у меня не была припаяна ножка RX- на PHY - работало по одному проводу. В результате после окончания пакета на 10МБит были еще дрыгания, которые интерпретировались PHY как начало нового фрейма. А MAC, как оказалось, даже такой в упор непакет все таки отбрасывает с установкой флага прерывания.

 

В общем, имейте в виду, что может происходить и такая ересь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...