Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Скорость выполнения кода на atmega640
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
Leonmezon
Цитата(rezident @ Jul 27 2009, 21:11) *
А вы только кол-во циклов сравнивали или результат тоже? В смысле, что программа правильно (или хотя бы одинаково smile.gif ) считает всеми способами? А то могу подсказать где кроется потенциальная ошибка. Константы отличные (отличающиеся) от типа int (от диапазона переменной типа int на данной архитектуре, в данном компиляторе) следует обозначать явным образом.
типа unsigned int - 32769U
типа long int - 12345678L
типа unsigned long int - 12345678UL
типа long long int - 1234567890LL
типа unsigned long long int - 1234567890ULL
типа float - 1.234567f В противном случае вот здесь константа в формате double может подставляться и вас спасаетвыручает только то, что float и double в вашем компиляторе одинаковой размерности (32 бита).

1. Результат проверил - одинаковый, с точностью до 1 еденицы числа (т.е. если в первом случае 12345678 то во втором и третьем (одинаково) 12345678 или 12345677 - иногда меняеться на 1 еденицу конечный результат - а это +-1 мкВ - меньше чем мзр. АЦП)
2. ImageCraft не требует указания явного обозначения констант, достаточно указать тип переменной и ее значение. (Да и не понимает он таких указаний - я попробывал, препроцессор дает ошибку).
3. Да только в тестовом я так записал константы: реально они пишуться как глобальные константы перед main() - пока ошибок небыло.
Код
const double Kd=8388608;
aaarrr
Цитата(Leonmezon @ Jul 27 2009, 20:18) *
впорос в константе KK сколько знаков после запятой оставлять?

Вам должно быть виднее. На сколько, например, 1.077 отражает реальность? Я бы не стал писать больше пяти.

Цитата(Leonmezon @ Jul 27 2009, 20:18) *
И второй Kd - может быть тип long - это как то влияет на размер кода (теоретически)?

Логично сначала вычесть в целых числах, затем умножить с плавающей запятой.

Код
  Kd=8388608;
  KK=1.2838840484619140625; // KK=KU/Kd
  rez=(C+(B<<8)+(A<<16));
  U = rez - Kd; // Отнимаем 0x800000  - для сдига в биполярный сигнал
  rez = (signed long)(U*KK); // Изменяем масштаб и преобразуем в микровольты и возращаем результат
Leonmezon
Цитата(aaarrr @ Jul 27 2009, 22:01) *
Вам должно быть виднее. На сколько, например, 1.077 отражает реальность? Я бы не стал писать больше пяти.


Логично сначала вычесть в целых числах, затем умножить с плавающей запятой.

Код
  Kd=8388608;
  KK=1.2838840484619140625; // KK=KU/Kd
  rez=(C+(B<<8)+(A<<16));
  U = rez - Kd; // Отнимаем 0x800000  - для сдвига в биполярный сигнал
  rez = (signed long)(U*KK); // Изменяем масштаб и преобразуем в микровольты и возвращаем результат

1. 1,077 отражает разброс С2-29 резисторов в входный аналоговых цепях - расчетное естественно, думаю есть смысл ограничиться 7 знаками (на время не все равно не влияет)
2. Логичнее, да и время выполнения уменьшаться на 21%.
Спасибо.

И все таки хотелось вернуться к первоначальному вопросу:
можно ли уменьшить время выполнения (естественно без учета ожидания флага от UART) кода преобразования и отправки байт по порту в функции void RS232(void) ? (Фактически можно ли как по другому long разбить на 4 байта с большей скоростью и тем же результатам (чтоб не переписывать программу на ЭВМ).
aaarrr
Цитата(Leonmezon @ Jul 28 2009, 00:12) *
И все таки хотелось вернуться к первоначальному вопросу:
можно ли уменьшить время выполнения (естественно без учета ожидания флага от UART) кода преобразования и отправки байт по порту в функции void RS232(void) ? (Фактически можно ли как по другому long разбить на 4 байта с большей скоростью и тем же результатам (чтоб не переписывать программу на ЭВМ).

По сравнению со временем ожидания флага все остальные расходы пренебрежимо малы. Фактически более 95% процессорного времени в этой процедуре пускается на ветер.
Leonmezon
Цитата(aaarrr @ Jul 28 2009, 00:15) *
По сравнению со временем ожидания флага все остальные расходы пренебрежимо малы.

Да, но пока я жду флаг - работают другие функции (в первую очередь прием новых данных): т.е. я имею ввиду что, написать функциию так, чтобы время ее выполнения равнялось фактически время ожидание флага умноженое на количество переданных байт (близко конечно).
aaarrr
Цитата(Leonmezon @ Jul 28 2009, 00:19) *
т.е. я имею ввиду что, написать функциию так, чтобы время ее выполнения равнялось фактически время ожидание флага умноженое на количество переданных байт (близко конечно).

По сравнению с тем временем, что Вы уже отыграли на сокращении вычислений, это 0.

Ну, модифицируйте цикл в передаче, полкопейки может быть выйграете:
Код
     for(i=0; i<600; i++)
     {
        long d = B1[i];

        UDR0 = (unsigned char)d;
        while (!(UCSR0A & (1<<UDRE0)));
        UDR0 = (unsigned char)(d >> 8);
        while (!(UCSR0A & (1<<UDRE0)));
        UDR0 = (unsigned char)(d >> 16);
        while (!(UCSR0A & (1<<UDRE0)));
        UDR0 = (unsigned char)(d >> 24);
        while (!(UCSR0A & (1<<UDRE0)));
     }
Leonmezon
Цитата(aaarrr @ Jul 28 2009, 00:26) *
По сравнению с тем временем, что Вы уже отыграли на сокращении вычислений, это 0.

Ну, модифицируйте цикл в передаче, полкопейки может быть выйграете:

Нет, выиграша нет (сдвиг на 24 требует почти 200 циклов).
А если немного переиначить вопрос: весь проект планируеться перевести на Xmega -в нем за счет DMA возможно будет получить выигреш ? Не сильно меняя при этом логику работы программы.
aaarrr
Цитата(Leonmezon @ Jul 28 2009, 00:54) *
Нет, выиграша нет (сдвиг на 24 требует почти 200 циклов).

Что-то слабо верится, что компилятор настолько туп. Сдвиг на 24 - это просто взять нужный байт. Или оптимизация выключена?

Цитата(Leonmezon @ Jul 28 2009, 00:54) *
А если немного переиначить вопрос: весь проект планируеться перевести на Xmega -в нем за счет DMA возможно будет получить выигреш ? Не сильно меняя при этом логику работы программы.

Ровным счетом то же самое Вы можете получить и сейчас, если перенесете работу с UART на прерывания.
rezident
Цитата(Leonmezon @ Jul 27 2009, 23:39) *
3. Да только в тестовом я так записал константы: реально они пишуться как глобальные константы перед main() - пока ошибок небыло.
Код
const double Kd=8388608;
Если вы объявляете их как инициализированные константы, то да, указывать не нужно. Т.к. тип этих констант вы уже определили. А вот если бы вы вдруг воспользовались командами препроцессора
Код
#define Kd 8388608
то грабли бы сработали в полный рост. laughing.gif
Leonmezon
Цитата(rezident @ Jul 28 2009, 20:01) *
Если вы объявляете их как инициализированные константы, то да, указывать не нужно. Т.к. тип этих констант вы уже определили. А вот если бы вы вдруг воспользовались командами препроцессора
Код
#define Kd 8388608
то грабли бы сработали в полный рост. laughing.gif

Не сработали biggrin.gif , я не люблю #define - через полгода сам не поймешь что писал. (А выдел я таких писателей - переименовывают названия порта чтоб легче - а потом куча вопросов че да как).
Лучше ответить на вопросов - DMA в Xmega может реально ускорить выполнения функции отправки байт (хотя массив с данными и так в ОЗУ находиться) - т.е. делать пересылку автоматом (я запустил и все пока не закончатся).


Цитата(aaarrr @ Jul 28 2009, 00:58) *
Что-то слабо верится, что компилятор настолько туп. Сдвиг на 24 - это просто взять нужный байт. Или оптимизация выключена?


Ровным счетом то же самое Вы можете получить и сейчас, если перенесете работу с UART на прерывания.

Оптимизация выключена (не могу обновить свою версию компилятора на расширенную) - так что нечего удивительного.
aaarrr
Цитата(Leonmezon @ Jul 28 2009, 20:24) *
Лучше ответить на вопросов - DMA в Xmega может реально ускорить выполнения функции отправки байт (хотя массив с данными и так в ОЗУ находиться) - т.е. делать пересылку автоматом (я запустил и все пока не закончатся).

Выбросьте из процедуры отправки все ожидания флага UART, и подсчитайте симулятором, что останется.
Еще раз говорю: это 0, ловить тут абсолютно нечего.
Leonmezon
Цитата(aaarrr @ Jul 28 2009, 20:26) *
Выбросьте из процедуры отправки все ожидания флага UART, и подсчитайте симулятором, что останется.
Еще раз говорю: это 0, ловить тут абсолютно нечего.

Я уже это сделал, но на переключенния задач все равно уходит время, а так его можно было бы уменьшить. И второе: думаю добавить простой цифровой фильтр: (режекторный готов - но он огромен для МК (на первый взгляд): необходимо перемножать массив на матрицу коэффициентов - явно могу не уложиться в 200-300 мс ) и второй - попробовать использовать медианный фильтр (может получиться меньше). Хотя этот вопрос еще требует проработки - какой из двух вариантов имеет наименьшую фазовую нелинейность.
aaarrr
А может, взять нормальные средства (можно и бесплатные) и, возможно, контроллер помощнее? На AVR и ICC свет клином не сошелся, как это ни странно.
Leonmezon
Цитата(aaarrr @ Jul 28 2009, 20:47) *
А может, взять нормальные средства (можно и бесплатные) и, возможно, контроллер помощнее? На AVR и ICC свет клином не сошелся, как это ни странно.

AVR не хочеться без нужды менять (тем более я его использую процентов на 20-30), думаю возможностей Xmega должно хватить на простой цифровой фильтр.
ICC сейчас меняю на новую версию с оптимизацией (кода и глобальной), но пока ну очень трудно обяснить нашему дистрибьютеру что хочу - у них человек уволился, а нового кто сображает пока нет - радует что еще и макетки не готовы по Xmega.
aaarrr
Цитата(Leonmezon @ Jul 28 2009, 20:57) *
AVR не хочеться без нужды менять (тем более я его использую процентов на 20-30), думаю возможностей Xmega должно хватить на простой цифровой фильтр.

Поменять AVR на XMega и поменять на что-то другое (дешевле и лучше, ага) - по-моему, принципиальной разницы по трудозатратам нет.
Rst7
Цитата
На AVR и ICC свет клином не сошелся, как это ни странно.


Особенно на ICC

Кстати, адептам целочисленных вычислений хотелось бы напомнить, что правильное умножение float*float практически эквивалентно перемножению long*long. В реализации для процессоров, не имеющих аппаратного деления (AVR в их числе) деление float'ов и long'ов тоже несильно отличается. О(1), не побоимся этого слова.
Leonmezon
Цитата(aaarrr @ Jul 28 2009, 21:07) *
Поменять AVR на XMega и поменять на что-то другое (дешевле и лучше, ага) - по-моему, принципиальной разницы по трудозатратам нет.

Зато есть финансовая разница! (Уже сейчас по Xmega есть все для начала работы (кроме макеток конечно - но я уже писал, это не просто макетка - на ней будет все чтобы сделать готовое изделие (то же направление)).
Основным сдерживающим фактором перехода на другой МК - это требования заказчика (по направлению измерения сейсмосигналов) - НИ какой цифровой обработки!!! (Не знаю, согласиться на простой фильтр или нет - а то может зря код оптимизировали). А без цифры - AVR за глаза хватает.
Да и переход на Xmega - вообще то довольно таки не трудный (DMA я и так не знаю в любом МК -все равно изучать, а шифрование - мне даром не нужно - специфика применения устройства) - остальные вопросы: АЦП, ЦАП, таймеры, порты, UART, SPI, прерывания, часы .... простые программы уже написал - жду железа чтоб пробовать. А большая часть кода - вообще не будет меняться при переходе.
aaarrr
Цитата(Rst7 @ Jul 28 2009, 21:14) *
Кстати, адептам целочисленных вычислений хотелось бы напомнить, что правильное умножение float*float практически эквивалентно перемножению long*long. В реализации для процессоров, не имеющих аппаратного деления (AVR в их числе) деление float'ов и long'ов тоже несильно отличается. О(1), не побоимся этого слова.

Зато появляется некоторый оверхед на перегнать туда-назад.

Цитата(Leonmezon @ Jul 28 2009, 21:35) *
Основным сдерживающим фактором перехода на другой МК - это требования заказчика (по направлению измерения сейсмосигналов) - НИ какой цифровой обработки!!!

Это, скорее, не сдерживающий фактор smile.gif
Просто колупаться с обкоцанным ICC - это как-то уж совсем не комильфо.
defunct
Цитата(Leonmezon @ Jul 25 2009, 19:24) *
Если вот так записать код, насколько будет быстрее первоначального?

Думаю что ни на сколько.
На мой взгляд основной тормоз у вас это блокировка отпраки данных длинным обработчиком INT6 (SPI +вычисления).

Если переделать алгоритм работы программы, а именно.

1. передачу по UART сделать по прерыванию.
2. Int6 сделать максимально возможно коротким - только взводить флажек готовности считывания АЦП.
3. Всю галиматью, с вычислениями и считыванием данных с АЦП через SPI, переместить в основной цикл программы. Выполнять ее тогда когда флажек готовности считывать АЦП установлен, после чего сбрасывать этот флажек.

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

Цитата(Leonmezon @ Jul 27 2009, 19:18) *
Начальный вариант: - 2976 циклов;
Мой вариант - 2021 циклов;

Даже начальный вариант с 2971 циклов, с лихвой годится для обработки любого тормозного сигма-дельта АЦП.
Банальная арифметка.
У Вас 3 АЦП, пусть 1KSPS, тогда всего циклов нужно:
2971 * 3 * 1000 = 8.913M

т.е. если будете тактировать МК частотой 14.7456Mhz, МК должен простаивать ~50% времени, даже в первоначальном варианте.
У вас же я так понимаю вообще 500SPS. Если же имеют место тормоза, проблема не в нехватке ресурса, не в проце и не в компиляторе, а неправильном распределении ресурса. (программа построена неверно).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.