|
AVR Studio эмуляция прерываний, После отработки подпрограммы перескакивает в конец цикла |
|
|
|
Apr 25 2009, 15:35
|
Участник

Группа: Участник
Сообщений: 46
Регистрация: 5-04-09
Пользователь №: 47 200

|
В теле блока main алгоритм внутри цикла while (1) {...}; За время счета алгоритма несколько раз срабатывает прерывание по таймеру. При эмуляции после первого прерывания курсор не возвращается на прежнее место в алгоритме, а перескакивает на последнюю строчку в цикле while (1). Повторного прогона цикла не происходит, а далее работают только прерывания. Как заставить программу продолжаться с того места, где произошло прерывание и заставить её крутиться в цикле while (1) ? Перешел на AVR Studio и WinAVR и подобного рода проблемы на уже отлаженных алгоритмах вылезают на ровном месте одна за другой
Сообщение отредактировал RAmsi - Apr 25 2009, 15:37
|
|
|
|
|
Apr 25 2009, 17:27
|
Частый гость
 
Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003

|
Цитата(RAmsi @ Apr 25 2009, 19:35)  В теле блока main алгоритм внутри цикла while (1) {...}; .... Перешел на AVR Studio и WinAVR и подобного рода проблемы на уже отлаженных алгоритмах вылезают на ровном месте одна за другой  Наверное со стеком проблемы, Вы модель контроллера в опциях симулятора и в опциях проекта (make файла) правильно установили? Телепаты, как обычно, в отпуске, поэтому неплохо бы на код глянуть и на настройки проекта тоже.
Сообщение отредактировал smac - Apr 25 2009, 17:27
|
|
|
|
|
Apr 26 2009, 16:47
|
Участник

Группа: Участник
Сообщений: 46
Регистрация: 5-04-09
Пользователь №: 47 200

|
Прогнал эмуляцию до упора. Проблема оказалась не в прерываниях. Вопрос к тем, кто использовал 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 алгоритм так тормозит. Кто-нибудь может поделиться опытом сравнения скорости вычисления в разных компиляторах?
|
|
|
|
|
Apr 28 2009, 08:01
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Видите ли. Отмечу несколько моментов.
1) Как ни старайся - результирующий код после разных компиляторов будет разный. Соответственно и скорость выполнения. Это зависит от выставленного уровня оптимизации, к примеру. Также от качества компилятора. По отзывам, WinGCC, как минимум не хуже чем CVAVR. В то же время, если хорошо знать особенности компилятора, то можно так "подправить" прогу на Си, что результирующий код будет намного лучше. При этом, как правило, код скомпилированный другим компилятором будет хуже.
Таким образом, не зная предысторию проекта, а также не видя его, не зная настроек, трудно оценить возможности по оптимизации.
2) сходя из вашего описания могу смело утверждать что у вас ошибка в самом алгоритме. Необходим приличный запас по производительности процессора, либо проект должен быть переработан таким образом, чтобы "не успевание" обработки не приводило к краху системы. Хотя так как вы делаете - вполне возможный и реальный подход. Сам иногда так поступаю. Только запас должен быть.
На вскидку можно предложить следующее. Прерывание измеряет само по себе. Усреднение и фильтрация - сама по себе. Вывод сам по себе. То есть цикл измерения будет больше чем цикл вывода.
|
|
|
|
|
Apr 28 2009, 12:12
|
Участник

Группа: Участник
Сообщений: 46
Регистрация: 5-04-09
Пользователь №: 47 200

|
Уровень оптимизации выставлял разный. Разницы почти никакой. В предыдущем сообщении я допустил ошибку - не 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.
Если будет время и желание посмотреть оба проекта - дайте Ваш адрес.
|
|
|
|
|
Apr 28 2009, 15:20
|
Участник

Группа: Новичок
Сообщений: 25
Регистрация: 17-05-08
Из: г.Монте Карло
Пользователь №: 37 579

|
RAmsi Как понять Ваше высказывание:
Ошибки в коде маловероятны т.к. оба проекта как две капли воды.
а листинги программ - тоже как две капли воды?
|
|
|
|
|
Apr 29 2009, 07:32
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(RAmsi @ Apr 25 2009, 19:35)  В теле блока main алгоритм внутри цикла while (1) {...}; За время счета алгоритма несколько раз срабатывает прерывание по таймеру. При эмуляции после первого прерывания курсор не возвращается на прежнее место в алгоритме, а перескакивает на последнюю строчку в цикле while (1). Повторного прогона цикла не происходит, а далее работают только прерывания. Как заставить программу продолжаться с того места, где произошло прерывание и заставить её крутиться в цикле while (1) ? Перешел на AVR Studio и WinAVR и подобного рода проблемы на уже отлаженных алгоритмах вылезают на ровном месте одна за другой  Симптомы указывают на неприменение 'volatile'. Анатолий.
|
|
|
|
|
Apr 30 2009, 11:37
|
Участник

Группа: Участник
Сообщений: 46
Регистрация: 5-04-09
Пользователь №: 47 200

|
Листинги программ естественно разные с учетом стандартов каждого компилятора. Проекты одинаковые в смысле алгоритма. Второй строился на базе первого.
Отключил все прерывания. В 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.
|
|
|
|
|
Apr 30 2009, 13:36
|
Участник

Группа: Участник
Сообщений: 46
Регистрация: 5-04-09
Пользователь №: 47 200

|
Прошу прощения. Массивы не double, а float.
|
|
|
|
|
Apr 30 2009, 13:56
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(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]); Ужос! Сплошные магические числа Пожалейте АВР. Если эти все коэффициенты так важны, то выберите другой контроллер. Только я в этом очень сомневаюсь. Можно с небольшой потерей точности перевести все на целочисленную арифметику и ускорить на порядок.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Apr 30 2009, 14:59
|
Участник

Группа: Участник
Сообщений: 46
Регистрация: 5-04-09
Пользователь №: 47 200

|
Смеяться пока могу над тем, что я еще не такой опытный чтобы понимать над чем смеяться. Поэтому и пришел на этот форум. AVR с CVAVR перемалывает пять таких блоков меньше чем за 2 мс и еще кучу оцифровок при этом делает и успевает еще данные через UART отправлять. И не только в эмуляторе но и в железе. В будущем процессор может и поменяю. Разрядность АЦП и ШИМ не устраивает. Целочисленную арифметику в WinAVR не пробовал. В CV точность коэффициентов с целочисленной арифметикой обеспечивал до 5-го или 6-го знака. Точно не припомню сколько был выигрыш по времени, но не больше 30%. А качество графиков на мониторе было отвратительным (шумы + смещение средней линии). Может и можно будет 2 или 3 знака убрать, но на данный момент это глобально ничего не решит. Если у кого-то возникнет желание помочь - жду адрес.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|