inco 1 12 апреля, 2011 Опубликовано 12 апреля, 2011 · Жалоба Была создана и более менее отлажена система на ките 4 цыклона. Теперь приехали боевые платы, ну и начал переносить проект на реальное железо. Ну и как обычно, то что работало на ките не захотело работать на реальной плате (кто бы сомневался). Но проблема оказалась ну очень какая-то странная. Уже все идеи кончились! Требуются идеи в каком направлении смотреть. По ходу поиска причин, написал максимально примитивный код, который не работает: volatile uint32_t flag = 0; volatile uint32_t counter = 0; void timeoutRestart(void); static void handle_eth0_timeout(void* context) { IOWR_ALTERA_AVALON_TIMER_STATUS(ETH_TIMEOUT_TIMER_BASE, 0); // Clear TO bit in status register printf("Hello from Nios II %d!\n", counter); // <- 1 counter++; // <- 2 flag = 1; } int main() { // Register timeout interrupt alt_ic_isr_register(ETH_TIMEOUT_TIMER_IRQ_INTERRUPT_CONTROLLER_ID, ETH_TIMEOUT_TIMER_IRQ, handle_eth0_timeout, NULL, NULL ); timeoutRestart(); while(1) { if(flag) { flag = 0; timeoutRestart(); } } return 0; } //! \brief Функция перезапуска таймера в случае прихода запроса по Ethernet. void timeoutRestart(void) { IOWR_ALTERA_AVALON_TIMER_PERIODL(ETH_TIMEOUT_TIMER_BASE, (uint16_t)ETH_TIMEOUT_TIMER_LOAD_VALUE ); IOWR_ALTERA_AVALON_TIMER_PERIODH(ETH_TIMEOUT_TIMER_BASE, (uint16_t)(ETH_TIMEOUT_TIMER_LOAD_VALUE >> 16) ); IOWR_ALTERA_AVALON_TIMER_CONTROL(ETH_TIMEOUT_TIMER_BASE, ALTERA_AVALON_TIMER_CONTROL_ITO_MSK | ALTERA_AVALON_TIMER_CONTROL_START_MSK ); // Restart timer with interrupt } Запускаю программу - счётчик counter не наращивается, сообщение печатается. Ставлю точку останова на метку (1) и на стартап. Запускаю на исполнение, срабатывают по очереди стартап и (1), то есть понятно, система перегружается. Ладно идём дальше. Останавливаюсь на точке (1) иду по шагам через printf и counter++ - счетчик наращивается нормально, printf тоже не вылетает(отрабатывает)! После этих двух шагов запускаю систему в динамике. Система перегружается (срабатывает стартап)! А вот теперь самое интересное! Останавливаюсь на точке (1). Открываю окно в отладчике (в эклипсе) Memory, чтобы посмотреть содержимое ячейки памяти где лежит counter. Делаю шаг смотрю в памяти счетчик изменился, стал равен 1. Запускаю дальше систему в динамике. Всё работает!!! Причём работает долго (больше часа точно!). Путём разных манипуляций выяснил, что пока не открою окно просмотра памяти в эклипсе, система работать не хочет! После того как в режиме просмотра содержимого памяти измениш counter с 0 на 1 (в пошаговом режиме), потом с системой можно делать всё что угодно, останавливать, стартовать, шагать, всё работает. Первая мысль была, что не тянет по частоте, но как тогда объяснить что после просмотра памяти она работает часами? По стеку тоже не понятно, опять же почему работает потом? Если printf с переменной, заменить на простой текст без параметров, тоже работает часами (не перегружается) счётчик наращивается. Причём работает сразу без манипуляций с эклипсом. Правда в этом случае вызывается не честный printf, а puts. Вобщем загадка природы! У меня идеи кончились! Может кто-то, что-то подскажет? В каком направлении копать? Квартус и ниос 9.1. Пробовал и в 10.1, тоже не работает, но с ним глубоко не копал. Проект написан на c++. По частоте тоже вроде запас большой. По ходу отладки выкинул из sopc 2/3 оборудования. Констрейны описаны. При требуемой частоте 50 МГц, квартус говорит допустимая 74 МГц. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vetal 0 12 апреля, 2011 Опубликовано 12 апреля, 2011 · Жалоба У вас для printf - блокирующий доступ по умолчанию. Если программный буфер UART будет переполнен, то функция вывода будет ожидать освобождения свободного места. Т.к. вызов происходит в прерывании - этого никогда не произойдет, пока не будут разрешены прерывания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 12 апреля, 2011 Опубликовано 12 апреля, 2011 · Жалоба У вас для printf - блокирующий доступ по умолчанию. Если программный буфер UART будет переполнен, то функция вывода будет ожидать освобождения свободного места. Т.к. вызов происходит в прерывании - этого никогда не произойдет, пока не будут разрешены прерывания. Так размер буфера jtag_uart по умолчанию 64 байта, а размер сообщения выводимого printf явно меньше. То есть, всё сообщение должно влезть в буфер. Частота вызова прерываний раз в 150 ms. К тому же, если бы printf блокировал систему, как тогда объяснить что после просмотра переменной в мэмори, система начинает работать нормально? И опять же, если бы printf блокировал систему, то она бы висла но не сбрасывалась. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
barabek 0 12 апреля, 2011 Опубликовано 12 апреля, 2011 · Жалоба А вот теперь самое интересное! Останавливаюсь на точке (1). Открываю окно в отладчике (в эклипсе) Memory, чтобы посмотреть содержимое ячейки памяти где лежит counter. Делаю шаг смотрю в памяти счетчик изменился, стал равен 1. Запускаю дальше систему в динамике. Всё работает!!! Причём работает долго (больше часа точно!). А какая у Вас используется память? У меня подобные аномалии были с самописным контроллером ддр-памяти. Если у Вас память внешняя попробуйте весь код запихнуть во внутреннюю. Если поместится, конечно же. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vetal 0 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба Так размер буфера jtag_uart по умолчанию 64 байта, а размер сообщения выводимого printf явно меньше. То есть, всё сообщение должно влезть в буфер. Тем более, что у вас jtag-uart. Там негарантированное время на опустошения этого буфера+его тактирование желательно на частоте не менее 24 МГЦ. Установите неблокирующий доступ для stdout. Лучше всего - вынесите printf в основную программу. И выводите содержимое счетчика когда он изменил свое значение. printf и/или sprintf могут хорошо повесить систему при неправильном использовании(особенно в прерывании). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба А какая у Вас используется память? У меня подобные аномалии были с самописным контроллером ддр-памяти. Если у Вас память внешняя попробуйте весь код запихнуть во внутреннюю. Если поместится, конечно же. Память внутренняя. Весь проект внутри кристалла ep4ce55, снаружи только PHY и еще несколько внешних интерфейсов (примитивных). Меня тоже вчера посетила мысля, что я при создании внутренней памяти (кроме ROM) отключил ее инициализацию. Но после того как я её включил поведение не изменилось! To Vetal: jtag_uart работает на системной частоте (50 МГц). На счет вынести printf сейчас попробую. Но мне он на самом деле в реальной системе не нужен вообще! Просто я минимальными средствами пытался воспроизвести поведение реальной системы, в которой тоже не работает прерывание и поведение похоже на вышеописанное. В реальной системе не работает прерывание от SGDMARX от TSE_MAC. Попробовал: переписал код: static void handle_eth0_timeout(void* context) { IOWR_ALTERA_AVALON_TIMER_STATUS(ETH_TIMEOUT_TIMER_BASE, 0); // Clear TO bit in status register flag = 1; counter++; } и в бесконечном цикле: while(1) { if(flag) { flag = 0; printf("Hello from Nios II %d!\n", counter); // <- 1 timeoutRestart(); // <- 2 } Система работает сразу, ничего не сбрасывается! Меняю местами строки (1) и (2) - система перегружается! То есть в данном случае printf каким-то образом действительно не успевает выводить сообщение и перегружает систему, но вот почему он ее перегружает, а не вешает мне не понятно? Ну да ладно, теперь придётся наверное воевать с реальной системой, похоже там возникает аналогичная ситуация. Но почему printf перегружает систему, а не вешает непонятно? Хотя один вывод из этих опытов наверное сделать всё таки можно - система живая и работает. Значит надо дальше искать ошибки чисто в программной части проекта, а не в проекте самой ПЛИС и sopc. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vadimuzzz 0 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба а с alt_printf пробовали? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба а с alt_printf пробовали? Нет не пробовал, я про такой и не знал. Дело в том что у меня написан свой my_printf, которым я пользуюсь (только с тем фукционалом, который мне нужен). Я же говорю, что то что тут приведено, это просто тестовая система, на которой я пытался проверить вообще система живёт или нет, потому и использовал printf. Просто когда я перенёс систему с кита на реальное железо и программа стала перегружаться, а кода там достаточно много начал разборки, потому как не понятно что всё таки не работает, то ли железо по частоте не тянет, то ли ошибки в проекте ПЛИС, то ли что-то с софтом, то ли что то с платой (железо новое, первая итерация, запустил только блоки питания ну и начал процесс...). В итоге весь софт снес написал примитивный тестовый проектик и он тоже стал перегружаться. Вот и задал вопрос про странное поведение, ведь после просмотра переменной в памяти, всё начинает работать - после этого у меня и наступил ступор! Как эти два события могут быть связаны!? Теперь после разъяснений про printf (которым я как уже сказал никогда не пользовался у себя в плисах) и изменения его местоположения -проект работает. Вот как запустил с утра, сколько там прошло, часа полтора, до сих пор работает. Сейчас печатает 39000... Так что свою функцию тест в любом случае уже выполнил. Сама система живёт! Значит надо копать именно софт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vadimuzzz 0 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба дело в том, что alt_printf работает без блокировок, насколько я помню Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vetal 0 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба дело в том, что alt_printf работает без блокировок, насколько я помню alt_printf работает без блокировок среды(env_lock). Для него возможно появление смеси ежа с носорогом при выводи из независимых мест(потоков, прерываний). Блокировки присутствуют в самом драйвере порта. По умолчанию для stdin, stdout и stderr установлен блокирующий режим записи(возврат управления только по окончании записи/чтения). Cнять можно примерно так: fcntl(0,F_SETFL,O_NONBLOCK); fcntl(1,F_SETFL,O_NONBLOCK); fcntl(2,F_SETFL,O_NONBLOCK); Еще одна возможная причина зависания - снятие прерывания до момента входа в его обработчик. Это интерпретируется системой, как break 0(останов) и в рабочей программе приводит к переходу в бесконечный цикл. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба Да, но если бы блокировка printf происходила в прерывании и он бы ждал окончания выдачи, то система бы висела на каком нибудь цикле ожидания в драйвере, но она почему-то перегружается? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vetal 0 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба но она почему-то перегружается? Значит происходит переполнение стека и аномальное поведение программы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vadimuzzz 0 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба Значит происходит переполнение стека и аномальное поведение программы. кстати, а такое может произойти, если постоянно вызывается обработчик прерывания (например, не сняли соотв. флаг)? типа, зашли в обработчик, прерывание не запретили, тут же обработчик вызывается опять и так до бесконечности.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vetal 0 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба кстати, а такое может произойти, если постоянно вызывается обработчик прерывания (например, не сняли соотв. флаг)? типа, зашли в обработчик, прерывание не запретили, тут же обработчик вызывается опять и так до бесконечности.. Такое может произойти если разрешены вложенные прерывания. Я таким не пользуюсь - мне хватает распределения приоритетов. Поведение HAL в этой области детально не изучал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 13 апреля, 2011 Опубликовано 13 апреля, 2011 · Жалоба Это всё понятно на сложных системах. Код программы приведен выше, в нём 3 строчки! Где там переполнение стека? Как я понимаю - она должна висеть на каком нибудь цикле ожидания, а она перегружается! Если бы она висела - тогда проблем нет, всё объяснимо! А в данном случае, единственное вразумительное объяснение если проект не тянет по частоте или питание плохое, но опять же при перестановки операторов проект работает! На данном этапе меня интересует только заключение, работает железо или нет (проект самой ПЛИС)! Проблемы софта пока не интересны! Но вот как сделать этот вывод, вот в этом и вопрос? (уже 90000...) 8-) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться