Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: AVR Studio эмуляция прерываний
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
RAmsi
В теле блока main алгоритм внутри цикла while (1) {...};
За время счета алгоритма несколько раз срабатывает прерывание по таймеру.
При эмуляции после первого прерывания курсор не возвращается на прежнее место в алгоритме, а перескакивает на последнюю строчку в цикле while (1). Повторного прогона цикла не происходит, а далее работают только прерывания.
Как заставить программу продолжаться с того места, где произошло прерывание и заставить её крутиться в цикле while (1) ?
Перешел на AVR Studio и WinAVR и подобного рода проблемы на уже отлаженных алгоритмах вылезают на ровном месте одна за другой crying.gif
smac
Цитата(RAmsi @ Apr 25 2009, 19:35) *
В теле блока main алгоритм внутри цикла while (1) {...};
....
Перешел на AVR Studio и WinAVR и подобного рода проблемы на уже отлаженных алгоритмах вылезают на ровном месте одна за другой crying.gif

Наверное со стеком проблемы, Вы модель контроллера в опциях симулятора и в опциях проекта (make файла) правильно установили? Телепаты, как обычно, в отпуске, поэтому неплохо бы на код глянуть и на настройки проекта тоже.
RAmsi
Прогнал эмуляцию до упора.
Проблема оказалась не в прерываниях.
Вопрос к тем, кто использовал CVAVR и WinAVR.

Кратко алгоритм следующий.
Таймер 0 настроен так, что делает 32 прерывания за 1/500 секунды. По прерыванию таймера происходит оцифровка входящего сигнала. За время следующего промежутка времени в 1\500 секунды вычисляется среднее значение за предыдущие 32 оцифровки, потом оно прогоняется через 7 каскадов цифровых фильтров и выводится через UART на компьютер. Параллельно происходят новые 32 оцифровки для расчета следующего значения.

При эмуляции с CVAVR весь цикл (прогонка через фильтры, передача по UART, параллельные 32 оцифровки в прерываниях) укладывался в тютельку в 1/500 секунды. Это 2 мс. Прекрасно этот алгоритм работал в железе.
При эмуляции в WinAVR на один цикл уходит примерно 30,5 мс. За это время таймер успевает сделать чуть более 120 прерываний. В настройках вроде везде выставил нужную частоту - 18,432 МГц.

Очень хочется верить, что я где-то ошибся в настройках. И не хочется верить, что после компиляции в WinAVR алгоритм так тормозит. Кто-нибудь может поделиться опытом сравнения скорости вычисления в разных компиляторах?
SasaVitebsk
Видите ли. Отмечу несколько моментов.

1) Как ни старайся - результирующий код после разных компиляторов будет разный. Соответственно и скорость выполнения.
Это зависит от выставленного уровня оптимизации, к примеру. Также от качества компилятора.
По отзывам, WinGCC, как минимум не хуже чем CVAVR.
В то же время, если хорошо знать особенности компилятора, то можно так "подправить" прогу на Си, что результирующий код будет намного лучше. При этом, как правило, код скомпилированный другим компилятором будет хуже.

Таким образом, не зная предысторию проекта, а также не видя его, не зная настроек, трудно оценить возможности по оптимизации.

2) сходя из вашего описания могу смело утверждать что у вас ошибка в самом алгоритме. Необходим приличный запас по производительности процессора, либо проект должен быть переработан таким образом, чтобы "не успевание" обработки не приводило к краху системы. Хотя так как вы делаете - вполне возможный и реальный подход. Сам иногда так поступаю. Только запас должен быть.

На вскидку можно предложить следующее.
Прерывание измеряет само по себе. Усреднение и фильтрация - сама по себе. Вывод сам по себе. То есть цикл измерения будет больше чем цикл вывода.
RAmsi
Уровень оптимизации выставлял разный. Разницы почти никакой. В предыдущем сообщении я допустил ошибку - не 30,5 мс, а 7,16 мс в WinAVR против 2 мс в CVAVR.

Ошибки в коде маловероятны т.к. оба проекта как две капли воды.

Общее время 32-х оцифровок - 312-313 мкс.
Основное время счета приходится на блоки фильтров:

xlp1[0]=xlp1[1]; xlp1[1]=xlp1[2]; xlp1[2]=xlp1[3]; xlp1[3]=xlp1[4];
xlp1[4]=input_data/21.46710182;
ylp1[0]=ylp1[1]; ylp1[1]=ylp1[2]; ylp1[2]=ylp1[3]; ylp1[3]=ylp1[4];
ylp1[4]=(xlp1[0]+xlp1[4]+4*(xlp1[1]+xlp1[3])+6*xlp1[2])-
(0.0301188750*ylp1[0])+(0.1826756978*ylp1[1])-
(0.6799785269*ylp1[2])+(0.7820951980*ylp1[3]);

Таких 5 штук и еще 2 поменьше.
Пробовал перевести счет на int (представлять дробные в виде результата деления двух больших целых) - точность сильно падает. Отказался.
Склоняюсь к переходу на CVAVR.

Если будет время и желание посмотреть оба проекта - дайте Ваш адрес.
SasaVitebsk
Я работаю вообще в IARе.
Речь не идёт об ошибках. Просто надо смотреть результирующий листинг. Разбираться в чём дело.
Может быть приведение разное и размерность. Трудно сказать. Уж больно велика разница.

Так а почему не изменить алгоритм?
GDI
Выполните код пошагово и посмотрите где у вас набегают лишние миллисекунды. Подозреваю что на вычислении фильтров и происходит это.
Верталь
RAmsi Как понять Ваше высказывание:

Ошибки в коде маловероятны т.к. оба проекта как две капли воды.

а листинги программ - тоже как две капли воды?
SasaVitebsk
А массивы xlp,ylp объявлены как int или как float?

Можно было бы высчитать результаты по каждому компилятору. smile.gif Ради любопытства.
aesok
Цитата(RAmsi @ Apr 25 2009, 19:35) *
В теле блока main алгоритм внутри цикла while (1) {...};
За время счета алгоритма несколько раз срабатывает прерывание по таймеру.
При эмуляции после первого прерывания курсор не возвращается на прежнее место в алгоритме, а перескакивает на последнюю строчку в цикле while (1). Повторного прогона цикла не происходит, а далее работают только прерывания.
Как заставить программу продолжаться с того места, где произошло прерывание и заставить её крутиться в цикле while (1) ?
Перешел на AVR Studio и WinAVR и подобного рода проблемы на уже отлаженных алгоритмах вылезают на ровном месте одна за другой crying.gif


Симптомы указывают на неприменение 'volatile'.

Анатолий.
RAmsi
Листинги программ естественно разные с учетом стандартов каждого компилятора. Проекты одинаковые в смысле алгоритма. Второй строился на базе первого.

Отключил все прерывания. В CVAVR в начале и в конце каждого блока добавил по инвертированию одной ноги свободного порта чтобы в VMLAB измерить интервал на осциллографе. Для чистоты эксперимента такое же инвертирование добавил и в WinAVR.

Куски кода:

CVAVR, VMLAB:
PORTC.3^=1;
xlp1[0]=xlp1[1]; xlp1[1]=xlp1[2]; xlp1[2]=xlp1[3]; xlp1[3]=xlp1[4];
xlp1[4]=input_data/21.46710182;
ylp1[0]=ylp1[1]; ylp1[1]=ylp1[2]; ylp1[2]=ylp1[3]; ylp1[3]=ylp1[4];
ylp1[4]=(xlp1[0]+xlp1[4]+4*(xlp1[1]+xlp1[3])+6*xlp1[2])-
(0.0301188750*ylp1[0])+(0.1826756978*ylp1[1])-
(0.6799785269*ylp1[2])+(0.7820951980*ylp1[3]);
PORTC.3^=1;

WinAVR, AVR Studio:
PORTC |= 1<<3;
xlp1[0]=xlp1[1]; xlp1[1]=xlp1[2]; xlp1[2]=xlp1[3]; xlp1[3]=xlp1[4];
xlp1[4]=input_data/21.46710182;
ylp1[0]=ylp1[1]; ylp1[1]=ylp1[2]; ylp1[2]=ylp1[3]; ylp1[3]=ylp1[4];
ylp1[4]=(xlp1[0]+xlp1[4]+4*(xlp1[1]+xlp1[3])+6*xlp1[2])-
(0.0301188750*ylp1[0])+(0.1826756978*ylp1[1])-
(0.6799785269*ylp1[2])+(0.7820951980*ylp1[3]);
PORTC |= 0<<3;

На выполнение первого по эмулятору ушло 145 мкс.
На выполнение второго в зависимости от оптимизации 946-949 мкс.
Львиная доля времени ушла на вычисление последней строчки фильтра.
В одном и другом проекте массив определен как double.
RAmsi
Прошу прощения. Массивы не double, а float.
_Pasha
Цитата(RAmsi @ Apr 30 2009, 14:37) *
Куски кода:
WinAVR, AVR Studio:
PORTC |= 1<<3;
*************
PORTC |= 0<<3;
На выполнение второго в зависимости от оптимизации 946-949 мкс.


Я вот из Ваших сообщений немного бреда выжал. Почитайте и посмейтесь над собой.
По делу: выложите листинг WinAVRовского кода. Без него ничего не понять. Оптимизацию оставьте -Os, с ней уж точно играться смысла нету.
Dog Pawlowa
Цитата(RAmsi @ Apr 30 2009, 14:37) *
xlp1[0]=xlp1[1]; xlp1[1]=xlp1[2]; xlp1[2]=xlp1[3]; xlp1[3]=xlp1[4];
xlp1[4]=input_data/21.46710182;
ylp1[0]=ylp1[1]; ylp1[1]=ylp1[2]; ylp1[2]=ylp1[3]; ylp1[3]=ylp1[4];
ylp1[4]=(xlp1[0]+xlp1[4]+4*(xlp1[1]+xlp1[3])+6*xlp1[2])-
(0.0301188750*ylp1[0])+(0.1826756978*ylp1[1])-
(0.6799785269*ylp1[2])+(0.7820951980*ylp1[3]);

Ужос! Сплошные магические числа cranky.gif
Пожалейте АВР. Если эти все коэффициенты так важны, то выберите другой контроллер.
Только я в этом очень сомневаюсь. Можно с небольшой потерей точности перевести все на целочисленную арифметику и ускорить на порядок.
RAmsi
Смеяться пока могу над тем, что я еще не такой опытный чтобы понимать над чем смеяться. Поэтому и пришел на этот форум. laughing.gif

AVR с CVAVR перемалывает пять таких блоков меньше чем за 2 мс и еще кучу оцифровок при этом делает и успевает еще данные через UART отправлять. И не только в эмуляторе но и в железе.
В будущем процессор может и поменяю. Разрядность АЦП и ШИМ не устраивает.

Целочисленную арифметику в WinAVR не пробовал. В CV точность коэффициентов с целочисленной арифметикой обеспечивал до 5-го или 6-го знака. Точно не припомню сколько был выигрыш по времени, но не больше 30%. А качество графиков на мониторе было отвратительным (шумы + смещение средней линии). Может и можно будет 2 или 3 знака убрать, но на данный момент это глобально ничего не решит.

Если у кого-то возникнет желание помочь - жду адрес.
aesok
Комндную строку линкера покажите, или Makefile.

Анатолий.
RAmsi
Спасибо
SysRq
Ммм.. Эта строчка ничего не делает:
Цитата(RAmsi @ Apr 30 2009, 15:37) *
PORTC |= 0<<3;
Измеряете вы в итоге хз что, т.к. конец импульса не понятно где будет (и будет ли).

Цитата(RAmsi @ Apr 30 2009, 19:31) *
Спасибо
Так вы именно с этим makefile измеряете? Тут же оптимизация отключена.
RAmsi
Строчки PORTC можно совсем выкинуть. Не в них дело. Они времени фактически не съедают. Съедает время расчет ylp1[4] с коэффициентами.
Время я замерял при разной оптимизации. Я писал об этом раньше.
Приклеил скриншоты. Разница в один шаг. Оптимизация Os.
SysRq
Из интереса поковырял.
Проверьте, что подключена libm.a (из Makefile не очевидно).

--

UPD:
Правильно ли я понимаю, что а) libm.a - оптимизированная именно для avr-libc мат. библиотека? б) для float арифметики без использования libm.a используюся built-in функции gcc?
aesok
Цитата(SysRq @ May 1 2009, 18:20) *
Правильно ли я понимаю, что а) libm.a - оптимизированная именно для avr-libc мат. библиотека? б) для float арифметики без использования libm.a используюся built-in функции gcc?


avr-libc-user-manual FAQ #2 и #31

Анатлолий.
RAmsi
Спасибо всем, кто откликнулся!
Библиотеку подключил. Работает отлично!
08.gif

Блок прогоняет за 114мкс. Быстрее чем в CVAVR!

SysRq, aesok, Вам отдельное спасибо! a14.gif beer.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.