|
Скорость выполнения кода на atmega640 |
|
|
|
Jul 24 2009, 11:12
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Просьба помочь с функцией отправки байт по RS232 от atmega640 (сама функция полностью работает, но необходимо ускорить ее выполнения (на ассемблер перейти не могу - его не знаю). // Функция передачи данных на ЭВМ по RS232 (масивы B1, B2 - создаю в ОЗУ, передаю по переменно взависимости от флагов. перед массив идут 5 0хF0 - заголовок. Код void RS232(void) { unsigned int i, j; unsigned char data[4]; signed long *p; p=(signed long*)data; flag_BUF=0; if (flag_B2==1) { UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; // Преобразуем signed long B1 и в ЭВМ for(i=0; i<600; i++) { *p=B1[i]; for (j=0; j<4; j++) { UDR0 = data[j]; while ( !( UCSR0A & (1<<UDRE0)) ) { }; } } } else { UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; UDR0 = 0xF0; while ( !( UCSR0A & (1<<UDRE0)) ) { }; // Преобразуем signed long B2 и в ЭВМ for(i=0; i<600; i++) { *p=B2[i]; for (j=0; j<4; j++) { UDR0 = data[j]; while ( !( UCSR0A & (1<<UDRE0)) ) { }; } } } }
Причина редактирования: Оформление цитаты исходника.
|
|
|
|
|
 |
Ответов
(1 - 68)
|
Jul 24 2009, 14:17
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(Непомнящий Евгений @ Jul 24 2009, 15:24)  А зачем вам ускорять скорость ее выполнения? Какая скорость rs232? По-идее, вы вполне будете ее выдерживать... Никаких тяжелых вычислений нет.
ps есть полезный тег code 1. Скорость RS232 - 115200 бит/с. 2. Прерывания - нельзя - эта функция работает постоянно, как готовы новые данные (т.е. заполнен буфер B1 или В2), а по прирыванию - идет заполнение буферов по переменно. Вот примерно как идет работа: (лишнее убрал) Код void main(void) { DDRF=0x0F; DDRC=0x0F; SpiInit(); uart0_init(); init_devices(); //Инициализация АЦП // Задание параметров работы АЦП // Бесконечный цикл с приемом данных и передачей по RS232 while(1) { if(flag_BUF==1) { RS232(); } NOP(); } }
Причина редактирования: Оформление цитаты исходника.
|
|
|
|
|
Jul 24 2009, 14:27
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Leonmezon @ Jul 24 2009, 17:17)  2. Прерывания - нельзя - эта функция работает постоянно... Вот именно по этой причине и нужны ПРЕРЫВАНИЯ или,как минимум буферизация, иначе эта фигня не "работает постоянно" а тупо жрет время в ожидании передачи байта. Проблема в том, что система постороена неправльно и никакими ASM тут ничем не поможешь. Цитата на ассемблер перейти не могу - его не знаю И Си тоже
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 24 2009, 14:30
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
я что-то не пойму. Вы не успеваете отправлять со скоростью 115200? В функции особо ускорять нечего. Она просто сует байты УАРТу и ждет, пока они отошлются. Если она не успевает их слать - возможно у вас какие-то "долгоиграющие" прерывания работают... Цитата(zltigo @ Jul 24 2009, 18:27)  Вот именно по этой причине и нужны ПРЕРЫВАНИЯ или,как минимум буферизация, иначе эта фигня не "работает постоянно" а тупо жрет время в ожидании передачи байта. Проблема в том, что система постороена неправльно и никакими ASM тут ничем не поможешь. Дык у топикстартера в главном цикле только эта функция и работает... А остальное, как я понял, в прерываниях. Если и эту функциональность перетащить в прерывания - разве получится какой-то выигрыш?
|
|
|
|
|
Jul 24 2009, 14:37
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Непомнящий Евгений @ Jul 24 2009, 17:30)  Дык у топикстартера в главном цикле только эта функция и работает... А остальное, как я понял, в прерываниях. Очень сильно сомневаюсь: Цитата // Бесконечный цикл с приемом данных и передачей по RS232 нет там прерываний. Совсем. Moderator: Тему перенес.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 24 2009, 15:52
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Перерыва в передачи байтов нет (данные принимаются на микроЭВМ, но хочу создать запас между посылками: сейчас примерно прием 400 мс, ожидае 600 мс - хочу увеличить время ожидания 800 мс и соотвественно за 200 мс все передовать) - простоя думаю как укорить этот процесс, чтобы был больший запас времени (физически скорость увеличить нельзя - 115200 бит/с - это максимум что может atmega), возможно можно увеличить скорость программно (т.е. уменьшить время между посылками). Весь алгоритм не привожу - так как неделю потрачу на его объяснение (сам струдом понимаю как его умудрился написать и при этом все работает). Само прерывание (причем таких три - от трех АЦП обрабатываются последовательно - сигнал RDY - обединен и заводиться на INT6): CODE / Функция получения данных от 1-го АЦП // Запускается только в том случае если прием разрешен, // и от АЦП пришел сигнал аппаратный о готовности данных - линия RDY signed long uzmerenie1(void) { unsigned int reg; unsigned long A, B, C; signed long rez; signed long K; double U; //Чтение регистра ADC Status PORTF&=~BIT(0); // CS1 установить в 0 - выбор 1 АЦП delay(); SpiWriteByte(0x04+0x40); reg=SpiReadByte(); // Выбор канала готовых данных (аппаратно RDY дает сигнал только о готовности данных,без указания канала switch (reg) { case 0x01: { // Установка чтение 0 канала данных //Устанавливаем регистр для чтения - выходные данные 24 бит - 3 байта SpiWriteByte(0x08+0x40); K=K11; } break; case 0x04: { // Установка чтение 1 канала данных //Устанавливаем регистр для чтения - выходные данные 24 бит - 3 байта SpiWriteByte(0x0A+0x40); K=K12; } break; default: { return (0x00);} } //Чтение данных из регистра АЦП // Читаем и заносим в буфер SPDR = 0x00; while (!(SPSR&0x80)); // ожидание готовности порта, прежде чем считывать A=SPDR; //считать SPDR - 1 байт SPDR = 0x00; while (!(SPSR&0x80)); // ожидание готовности порта, прежде чем считывать B=SPDR; //считать SPDR - 2 байт SPDR = 0x00; while (!(SPSR&0x80)); // ожидание готовности порта, прежде чем считывать C=SPDR; //считать SPDR - 3 байт // Закрываем АЦП PORTF|=BIT(0); // CS1 установить в 1 // Получаем длиное целое из полученных байт // с учетом что первым идет старший байт rez=(C+(B<<8)+(A<<16)); // Далее преобразуем с типу double и Преобразуем к напряжению U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В // Отнимаем 10 В - для сдига в биполярный сигнал - получаем изменение напряжения от -10 до 10В U=U-10; U=U*KU; // Преобразуем в микровольты и возращаем результат rez=(signed long)(U*1000000); rez=rez-K; return (rez); }
Причина редактирования: Оформление цитаты исходника.
|
|
|
|
|
Jul 24 2009, 15:59
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Оптимизацию советую начать отсюда: Код U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В Работа с длинной плавучкой в прерывании, мягко говоря, изрядно все затормозит. Ускорить void RS232(void) не получится - если он не отрабатывает за 200 с небольшим миллисекунд при скорости UART 115200, значит ему мешают тормозные прерывания. P.S. Пожалуйста, пользуйтесь тегами [сode][/сode], иначе вашу программу просто никто не станет читать.
|
|
|
|
|
Jul 24 2009, 16:12
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 24 2009, 19:59)  Оптимизацию советую начать отсюда: Код U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В Работа с длинной плавучкой в прерывании, мягко говоря, изрядно все затормозит. Ускорить void RS232(void) не получится - если он не отрабатывает за 200 с небольшим миллисекунд при скорости UART 115200, значит ему мешают тормозные прерывания. P.S. Пожалуйста, пользуйтесь тегами [сode][/сode], иначе вашу программу просто никто не станет читать. А как? Не совсем понятно чем можно заменить (данные на ЭВМ должны идти уже в напряжении). Значения коээфициентов: (боле понятно будет) const signed int K11=-831; // программный учет смещения в 1 канале 1 АЦП вычисляеться на ЭВМ за 1 час const signed int K12=-999; // программный учет смещения в 2 канале 1 АЦП вычисляеться на ЭВМ за 1 час const double KU=1; // коэффициент передачи сигнала в аналоговой части 1.077 const double Kd=16777215; // длина всего диапазона для +-10В - 0xFFFFFF
|
|
|
|
|
Jul 24 2009, 16:24
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(Leonmezon @ Jul 24 2009, 20:12)  А как? U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В rez=(signed long)(U*1000000); Ну, как минимум, заменить 3 операции умножения / деления одной Либо двумя, но без плавучки U=(((long long)rez)*20000000)/Kd; А вообще, уже писали. Подход неверный вкорне. Работа с UARTом должна происходить по прерываниям в фоне, а в это время обсчитывается следующий пакет.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Jul 24 2009, 17:02
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(MrYuran @ Jul 24 2009, 20:24)  U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В rez=(signed long)(U*1000000);
Ну, как минимум, заменить 3 операции умножения / деления одной Либо двумя, но без плавучки
U=(((long long)rez)*20000000)/Kd;
А вообще, уже писали. Подход неверный вкорне.
Работа с UARTом должна происходить по прерываниям в фоне, а в это время обсчитывается следующий пакет. Просчитал - не получить, я ограничен возможностями компилятора ( максим на тип signed long - 4 байта), а для работы в чисто целочисленном (без использования плавующей точки - (плавующая то же 4 байтная)) - надо 8 байт. Компилятор - менять не буду! Может конструкция switch {} заменить на if? (здесь можно что то выиграть)
|
|
|
|
|
Jul 24 2009, 17:22
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Leonmezon @ Jul 24 2009, 21:02)  Просчитал - не получить, я ограничен возможностями компилятора ( максим на тип signed long - 4 байта), а для работы в чисто целочисленном (без использования плавующей точки - (плавующая то же 4 байтная)) - надо 8 байт. Компилятор - менять не буду! Вы ограничены не компилятором, а собственным воображением. У компилятора, наверное, есть тип long long. Но это все равно не поможет, если сначала делить на 16777215, а затем умножать на 1000000. С таким подходом никакой разрядности не хватит, надо менять образ мышления. Цитата(Leonmezon @ Jul 24 2009, 21:02)  Может конструкция switch {} заменить на if? (здесь можно что то выиграть) По сравнению с остальным это такая мелочь, что не выйграете ровным счетом ничего.
|
|
|
|
|
Jul 24 2009, 17:44
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 24 2009, 21:22)  Вы ограничены не компилятором, а собственным воображением. У компилятора, наверное, есть тип long long. Но это все равно не поможет, если сначала делить на 16777215, а затем умножать на 1000000. С таким подходом никакой разрядности не хватит, надо менять образ мышления.
По сравнению с остальным это такая мелочь, что не выйграете ровным счетом ничего. Причем здесь мышление не совсем понятно, код в целочисленном виде я могу записать вот так (чтобы не было точно double!!!). Код rez=((rez*215540000)/16777215)-107700000; // где при максимальном rez=0xFFFFFF - получим в первой скобке число 3616160921100000=0xCD8E113271EE0 - 8байт
|
|
|
|
|
Jul 24 2009, 18:14
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 24 2009, 22:05)  Да не нужно заниматься ерундой и делить на 16777215! В самом начале Вы получаете 24-х битное число, так и работайте дальше с ним. Как я могу обойтись без деления, если мне необходимо перевести из коды АЦП в напряжение??? Весь диапазон: 20 В - или 0xFFFFFF в кодах, используя простое правило пропрции - получаем искомое, как можно еще иначе? (причем если значения коэффициентов: масштабного и учет смещения в Вольтах).
|
|
|
|
|
Jul 24 2009, 18:41
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Leonmezon @ Jul 25 2009, 00:14)  Как я могу обойтись без деления, если мне необходимо перевести из коды АЦП в напряжение??? Вы огласите сначала, с какой точностью вам нужно проводить измерения? А то мучаетесь тут с каким-то микровольтами и 24-разрядным результатом измерения АЦП, а требуется, допустим, 0,1% относительная приведенная погрешность. Для этого при диапазоне входных напряжений -10В...+10В достаточно измерять с разрешением (10В-(-10В))/(0,1%*100)<=20мВ скажем 1мВ. Для представления напряжения с точностью 1мВ в указанном диапазоне вполне достаточно 16-и разрядного знакового числа. И соответственно типа long вполне хватит для всех вычислений.
|
|
|
|
|
Jul 24 2009, 18:58
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 24 2009, 22:40)  Деление на 16777215 и умножение на 20000000 эквивалентно умножению 1.1921. В целых числах делается умножением и сдвигом. Коэффициенты пересчитайте отдельно. 1. Для меня это сложно! Умножать на 1,1921 со сдвигом. (точнее правильно с масштабом 1,077 умножить надо на К=1,283884124987371265135482855766 чтобы использовать уменьшению формулу: rez=(rez*К)-107700000; 2. Точность необходима полная - все 24 разряда.
|
|
|
|
|
Jul 24 2009, 19:10
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(rezident @ Jul 24 2009, 23:02)  Ерунду написали. АЦП измеряет напряжение. Напряжение принято выражать в Вольтах. С какой относительной погрешностью (в процентах) и в каком диапазоне напряжений (в Вольтах) вам нужно проводить измерения? Повторюсь - 24 разряда АЦП или +- 10 В с максимальной точностью что дает АЦП (по заявленным характеристикам без ухищрений +- 150 мкВ).
|
|
|
|
|
Jul 24 2009, 19:52
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(rezident @ Jul 24 2009, 23:25)  150мкВ при опоре 2,5В (или 1,25В?) это уже никак не "все 24 разряда". Плюс потеря точности на делителе/преобразователе, который приводит диапазон -10В...+10В ко входному 2,5В(1,25В). В результате относительная точность измерения входного напряжения скорее всего не лучше 0,01%. Но вы конечно же можете продолжать использовать "все 24-разряда" для вычислений.  Вы не правы! Для начала посмотрите даташит на АЦП (AD7732) где при ИОН 2,5 В за счет внутренних резисторов !!!!!!! (выполненых с точность не менее 0.006 %) и получаеться заявленная мною неустойчивость, так что реально необходимы все разряды АЦП без округления. Между прочим - я просил код помочь оптимизировать на быстродействие - а не рассказыват о точности АЦП - в любом случае Ваши знания не точнее информации из даташита!
|
|
|
|
|
Jul 25 2009, 03:25
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
Цена деления 1,2 мкВ при точности ±150 мкВ.. Кстати, вы, вероятно, ошиблись. В описании на AD7732 явно указано «% of FSR», а не процент от опорного. Получается около ±6 мВ. По поводу оптимизации. Посмотрите в таком направлении, может что и получится: Думаю, не обязательно перемножать каждый раз то, что можно перемножить заранее. «Используя простое правило пропорции», никто вас не обязывает брать крайние значения. Например можно взять половину от hFFFFFF. rez = (Kd - h7FFFFF) * (10^7*KU) / h7FFFFF1. Вычитание со знаком; 2. Умножение (6 байт включая знак!). 3. Деление (фактически сдвиг на 7 бит с отбросом двух байт с сохранением знака). Осталось одно умножение, которое, видимо, можно сделать заблаговременно (10^7 * Ka). Погрешность у меня получилась ~1,2 мкВ при цене деления 1,2 мкВ. Вам правильно указали, что надо определиться с точностью. И тогда, может быть, выбрать еще более приятную всё ту же пропорцию. Удачи.
Сообщение отредактировал x736C - Jul 25 2009, 03:34
|
|
|
|
|
Jul 25 2009, 16:24
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Если вот так записать код, насколько будет быстрее первоначального? (и что еще можно упростить, без применения ухишрений (типа сдвига...). И можно что то сделать с отниманием 1 (или она мало занимает кода). Код const signed int K11=-831; // программный учет смещения в 1 канале 1 АЦП const signed int K12=-999; // программный учет смещения в 2 канале 1 АЦП const double KU=10770000; // коэффициент передачи сигнала в аналоговой части 1.077 умноженный на 1000000х10 const double Kd=8388608; // половина всего диапазона для +-10В - 0xFFFFFF/2 . . // Функция получения данных от 1-го АЦП signed long uzmerenie1(void) { . . . rez=(C+(B<<8)+(A<<16)); /* Далее преобразуем с типу double и преобразуем к напряжению с упрощением операций, конечный результат: напряжение от -10 В до 10 В в микровольтах*/ U=((double)(rez))/Kd; U=U-1; // Отнимаем 1 - для сдига в биполярный сигнал rez=(signed long)(U*KU); // Изменяем масштаб и преобразуем в микровольты и возращаем результат rez=rez-K; //Учитываем смещение в каждом из каналов АЦП: 1К - К11; 2К- К12 return (rez); }
Сообщение отредактировал Leonmezon - Jul 25 2009, 16:26
|
|
|
|
|
Jul 25 2009, 16:54
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
Я написал просто деление. Дальше в скобках уточнил, что процедура деления в вашем случае достаточно быстрая. Не надо рассматривать это, как ухищрение. Не приводите перед делением rez к типу double. У вас абсолютно целочисленное деление на (2^23 - 1). Все в signed long.Напишите, пожалуйста, позже в теме, насколько уменьшилось время выполнения процедуры. Интересно. На какой частоте работает контроллер? Цитата(Leonmezon @ Jul 25 2009, 20:24)  И можно что то сделать с отниманием 1 (или она мало занимает кода). Думаю, что это не тот случай, чтоб оптимизировать вычитание единицы. Оставьте так
Сообщение отредактировал x736C - Jul 25 2009, 16:57
|
|
|
|
|
Jul 25 2009, 17:01
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(x736C @ Jul 25 2009, 20:48)  Я написал просто деление. Дальше в скобках уточнил, что процедура деления в вашем случае достаточно быстрая. Не надо рассматривать это, как ухищрение. Не переводите перед делением rez к типу double. У вас абсолютно целочисленное деление на (2^23 - 1). Все в signed long.
Напишите, пожалуйста, позже в теме, насколько уменьшилось время выполнения процедуры. Интересно. На какой частоте работает контроллер? 1. По времени - попробую на работ- напишу. (Хотя тяжело точно отследить - примерно будет только). 2. В целочисленных нельзя (правда я не уверен - как на самом деле будет происходить преобразования типов: сначала результат, потом преобразование или нет): U=rez/Kd - если rez и Kd целочисленные - то результат будет 0 при rez<Kd? 3. Частота 14,... МГц - хотя сейчас думаю перевести на Xmega - с частотой 14,...х2 = 28,.. МГц (в теме Xmega писал уже) 4. В принципе и сейчас все работает (и очень хорошо),но появился датчик (с собственным шумом 300 нВ) и для работы с ним планирую сделать запас времени, чтобы сняв 200 выборок за 1 сек прогнать через простой режекторный цифровой фильтр в микроконтроллере (повысить точность измерений) - для этого и еще как бы выиграть еще время, т.е. перед отправкой буфера (2400 байт) по RS232 успеть 200-300 мс прогнать через фильтр. (Фильтр пишу не я - человек на них собаку съел - но просит запас по времени на работу фильтра)
|
|
|
|
|
Jul 25 2009, 17:28
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
1. Как оцениваете время выполнения функции? Симулятор не может посчитать? 2. Результат будет правильным. Типы менять туда-сюда не надо в вашем случае. 3. 28 — огромная частота  4.1. Если вы поверите в прерывания, то сможете многое выполнять параллельно. Например, работать с данными и отсылать их одновременно, выполняя что-то третье. 4.2. 200-300 мс — огромное время  4.3. 1 сек — «..200 выборок за 1 сек прогнать через...» «...успеть 200-300 мс прогнать через...» Сколько в итоге? Если не секрет, какого рода данные с датчика? Что-то периодичное? Почему такие точности? P. S. Неужели ассемблер окончательно отмирает
Сообщение отредактировал x736C - Jul 25 2009, 17:29
|
|
|
|
|
Jul 25 2009, 18:19
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(x736C @ Jul 25 2009, 21:28)  1. Как оцениваете время выполнения функции? Симулятор не может посчитать? 2. Результат будет правильным. Типы менять туда-сюда не надо в вашем случае. 3. 28 — огромная частота  4.1. Если вы поверите в прерывания, то сможете многое выполнять параллельно. Например, работать с данными и отсылать их одновременно, выполняя что-то третье. 4.2. 200-300 мс — огромное время  4.3. 1 сек — «..200 выборок за 1 сек прогнать через...» «...успеть 200-300 мс прогнать через...» Сколько в итоге? Если не секрет, какого рода данные с датчика? Что-то периодичное? Почему такие точности? P. S. Неужели ассемблер окончательно отмирает  1. Я и на симулятор не могу дома (компилятор не компилирует код - только до 4 кБ - а у меня больше - на работе - лицензия - тогда и проверю). 2. Насчет типов - проверю. 3. 28 - это не много. 4.1. На прерывания - нельзя, ввиду того что на прерываниях сидят 3 АЦП, плюс прерывание синхронизации от GPS. 4.2. Не очень верно написал: по внешнему такту, а запускаю 3 АЦП на оцифровку данных - с частотой 200 Гц - получаю за 1 сек - 600 значений (три канала) и останавливаюсь на 10 мкс, приходит новый такт и процесс повторяться по АЦП, при этом данные принятые за предыдущею секунду передаются по RS232 (надо успеть до нового такта). Т.е. получаем трехканальную систему синхронной оцифровки которая работает с задержкой во времени на 1 сек. (Заказчика устраивает). 4.3. Датчик - сейсмодатчик, последний с динамическим диапазоном 145 дБ (но самый верх можно не мерять - но выше 9 балов по шкале Рихтера можно не мерять...) 5. На ассемблере - это тяжка написать, если только не критические функции...
|
|
|
|
|
Jul 25 2009, 18:23
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(x736C @ Jul 25 2009, 21:28)  2. Результат будет правильным. Типы менять туда-сюда не надо в вашем случае. Не будет. Цитата(x736C @ Jul 25 2009, 21:28)  P. S. Неужели ассемблер окончательно отмирает  Ну и причем тут ассемблер? 2 Leonmezon: Во-первых, 24-х значащих бит у Вас не будет никогда, просто примите это как данность. Во-вторых сдвиг является не "ухищрением", а нормальным методом деления и умножения на степень двойки. И освойте тип long long. Получите что-то типа: Код const signed int K11=-831; // программный учет смещения в 1 канале 1 АЦП const signed int K12=-999; // программный учет смещения в 2 канале 1 АЦП const long KU=10770000; // коэффициент передачи сигнала в аналоговой части 1.077 умноженный на 1000000х10 const double Kd=8388608; // половина всего диапазона для +-10В - 0xFFFFFF/2 . . // Функция получения данных от 1-го АЦП signed long uzmerenie1(void) { long long U; . . . U=(C+(B<<8)+(A<<16)); U -= Kd; // Отнимаем 1 - для сдига в биполярный сигнал rez = (U * KU) >> 23; // Изменяем масштаб и преобразуем в микровольты и возращаем результат rez=rez-K; //Учитываем смещение в каждом из каналов АЦП: 1К - К11; 2К- К12 return (rez); Хотя и это дикий маразм, т.к. я уверен, что и 1.077 и (10000000 / 8388608) можно упихать в один восьмибитный коэффициент, оставшись при этом в пределах 32-х битной арифметики, безо всякого ущерба для конечного результата.
|
|
|
|
|
Jul 25 2009, 18:43
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
Цитата(aaarrr @ Jul 25 2009, 22:23)  Не будет.
Ну и причем тут ассемблер? То есть поделить signed long на signed long нельзя? Каким будет результат при отрицательном значении делимого? Не знал этого, спасибо за замечание. По поводу ассемблера имел в виду не то, что надо все и вся на нем писать, а то что иногда надо понимать то, что выполняет Си-комплилятор, понимая процесс чуть глубже. Опыт использования ассемблера в этом смысле только плюс.
|
|
|
|
|
Jul 25 2009, 18:48
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(x736C @ Jul 25 2009, 22:43)  То есть поделить signed long на signed long нельзя? Каким будет результат при отрицательном значении делимого? Не знал этого, спасибо за замечание. Можно, конечно. Просто нет смысла делить, условно говоря, 12345 на 123456. Цитата(Leonmezon @ Jul 25 2009, 22:43)  long long - длиное целое 8 байтовое? ( Если да, то у меня только до 4 байт). Уверены? И double тоже 32-х битный?
|
|
|
|
|
Jul 25 2009, 19:11
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 25 2009, 22:48)  Можно, конечно. Просто нет смысла делить, условно говоря, 12345 на 123456.
Уверены? И double тоже 32-х битный? Да; long, float, double - 4 байтовые. Компилятор ICC AVR 7.22 STD. Я често не знаю, но только вроде в IAR есть long long 8 байт. По делению как раз понятно (я еще вчера об этом говорил) 12345/123456= 0 в целочисленном вычеслении.
Сообщение отредактировал Leonmezon - Jul 25 2009, 19:13
|
|
|
|
|
Jul 25 2009, 19:24
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
Цитата(Leonmezon @ Jul 25 2009, 23:11)  По делению как раз понятно (я еще вчера об этом говорил) 12345/123456= 0 в целочисленном вычеслении. Понял, что имел в виду aaarrr.В целочисленном исчислении нет знака? -1234567/123456= 0 ? Все зависит от компилятора, конечно. Такая («12345/123456») ситуация, как привел aaarrr, когда делимое меньше делителя, в приведенной мной последовательности вычислений не возникает никогда.
Сообщение отредактировал x736C - Jul 25 2009, 19:27
|
|
|
|
|
Jul 25 2009, 19:41
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(x736C @ Jul 25 2009, 23:24)  Понял, что имел в виду aaarrr.
В целочисленном исчислении нет знака? -1234567/123456= 0 ? Все зависит от компилятора, конечно.
Такая («12345/123456») ситуация, как привел aaarrr, когда делимое меньше делителя, в приведенной мной последовательности вычислений не возникает никогда. Нет, может быть: рассуждения относяться к формуле U=((double)(rez))/Kd; - чтоб она правильно работала rez - надо перевести в double. rez может быть от 0 до 0хFFFFFF, а Kd=0х800000
|
|
|
|
|
Jul 25 2009, 19:44
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(x736C @ Jul 25 2009, 23:24)  Такая («12345/123456») ситуация, как привел aaarrr, когда делимое меньше делителя, в приведенной мной последовательности вычислений не возникает никогда. Дык мы же не про вашу последовательность говорили, а про это: Цитата(x736C @ Jul 25 2009, 20:54)  Не приводите перед делением rez к типу double. У вас абсолютно целочисленное деление на (2^23 - 1). Все в signed long. Ладно, не важно, если long long все равно нет. 2 Leonmezon: Тогда оставьте в плавучке одно умножение, а еще лучше поручите все вычисления принимающей стороне.
|
|
|
|
|
Jul 25 2009, 20:02
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
Понятно. Запутался слегка. Из Kd можно убрать лишнюю единичку, на точность не влияет. Код Kd = 0x7FFFFF U=U-Kd; // Отнимаем Kd - для сдвига в биполярный сигнал rez=(signed long)(U*KU); // Изменяем масштаб и преобразуем в микровольты и возвращаем результат U=((signed long)(rez))/Kd;
rez=rez-K; //Учитываем смещение в каждом из каналов АЦП: 1К - К11; 2К- К12 return (rez); А так?
Сообщение отредактировал x736C - Jul 25 2009, 20:11
|
|
|
|
|
Jul 25 2009, 20:21
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 25 2009, 23:44)  Дык мы же не про вашу последовательность говорили, а про это:
Ладно, не важно, если long long все равно нет.
2 Leonmezon: Тогда оставьте в плавучке одно умножение, а еще лучше поручите все вычисления принимающей стороне. Принимающей стороне нельзя (там программа должна быть абсолютно одинаковая в 50 комплектах). Оставлю одно операцию с double. Возможно только в будущем (зимой) получиться перейти на целочисленную математику, я списывался с ImageCraft - они наняли програмистов под Xmega (пишут генератор кода,примеры..., какие утилиты - возможно и добавять новые типы данных, сейчас есть только double 8 байтный профессиональной версии, но он не решает задачи). (да обязательно требование от заказчика - лицензия, а на IAR перейти - не вариант, дорого). Спасибо за подсказки. Цитата(x736C @ Jul 26 2009, 00:02)  Понятно. Запутался слегка. Из Kd можно убрать лишнюю единичку, на точность не влияет. Код Kd = 0x7FFFFF U=U-Kd; // Отнимаем Kd - для сдвига в биполярный сигнал rez=(signed long)(U*KU); // Изменяем масштаб и преобразуем в микровольты и возвращаем результат U=((signed long)(rez))/Kd;
rez=rez-K; //Учитываем смещение в каждом из каналов АЦП: 1К - К11; 2К- К12 return (rez); А так? Не получиться, необходмо 6 байт в rez=(signed long)(U*KU); , а есть только 4! (При максимальном значении 10 и -10 В). Ладно, как не крути - 1 с плавующей умножени все равно необходимо. (В любом случае лучше чем 4!).
|
|
|
|
|
Jul 27 2009, 10:45
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(x736C @ Jul 26 2009, 00:45)  Понятно. Это как раз то, чего я не мог понять в диалоге между вами и aaarrr. Ну удачи вам. Время исполнения кода (в симуляторе) снизилось на 31%. (Много времени занимает деление - попробую и его убрать, на сдвиг).
|
|
|
|
|
Jul 27 2009, 16:18
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 27 2009, 17:07)  А зачем Вы его (деление) вообще оставили? Согласен, деление увеличивает время исполнения в 2 раза: Начальный вариант: - 2976 циклов; Мой вариант - 2021 циклов; Ваш вариант (без деления но в double) - 1000 циклов, впорос в константе KK сколько знаков после запятой оставлять? И второй Kd - может быть тип long - это как то влияет на размер кода (теоретически)? Вот тестовый файл: Код //ICC-AVR application builder : 27.07.2009 20:16:20 // Target : M640 // Crystal: 14.7456Mhz
#include <iom640v.h> #include <macros.h>
void main(void) { unsigned long A, B, C; signed long rez; double U, KU, Kd, KK; A=128; B=25; C=55;
// Начальный вариант rez=(C+(B<<8)+(A<<16)); KU=1.077; U=(((double)(rez))*20)/0xFFFFFF; // Получаем напряжение от 0 до 20 В // Отнимаем 10 В - для сдига в биполярный сигнал - получаем изменение напряжения от -10 до 10В U=U-10; U=U*KU; // Преобразуем в микровольты и возращаем результат rez=(signed long)(U*1000000); // Мой вариант KU=10770000; Kd=8388608; U=(C+(B<<8)+(A<<16)); // Далее преобразуем с типу double и Преобразуем к напряжению U=U/Kd; U=U-1; // Отнимаем 1 - для сдига в биполярный сигнал rez=(signed long)(U*KU); // Изменяем масштаб и преобразуем в микровольты и возращаем результат // Предложенный вариант KU=10770000; Kd=8388608; KK=1.2838840484619140625; // KK=KU/Kd U=(C+(B<<8)+(A<<16)); U -= Kd; // Отнимаем 0x800000 - для сдига в биполярный сигнал rez = (signed long)(U*KK); // Изменяем масштаб и преобразуем в микровольты и возращаем результат while(1) {;} }
|
|
|
|
|
Jul 27 2009, 17:11
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Leonmezon @ Jul 27 2009, 22:18)  Вот тестовый файл: А вы только кол-во циклов сравнивали или результат тоже? В смысле, что программа правильно (или хотя бы одинаково  ) считает всеми способами? А то могу подсказать где кроется потенциальная ошибка. Константы отличные (отличающиеся) от типа int (от диапазона переменной типа int на данной архитектуре, в данном компиляторе) следует обозначать явным образом. типа unsigned int - 32769 Uтипа long int - 12345678 Lтипа unsigned long int - 12345678 ULтипа long long int - 1234567890 LLтипа unsigned long long int - 1234567890 ULLтипа float - 1.234567 f В противном случае вот здесь константа в формате double может подставляться и вас спасаетвыручает только то, что float и double в вашем компиляторе одинаковой размерности (32 бита).
|
|
|
|
|
Jul 27 2009, 17:39
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(rezident @ Jul 27 2009, 21:11)  А вы только кол-во циклов сравнивали или результат тоже? В смысле, что программа правильно (или хотя бы одинаково  ) считает всеми способами? А то могу подсказать где кроется потенциальная ошибка. Константы отличные (отличающиеся) от типа int (от диапазона переменной типа int на данной архитектуре, в данном компиляторе) следует обозначать явным образом. типа unsigned int - 32769 Uтипа long int - 12345678 Lтипа unsigned long int - 12345678 ULтипа long long int - 1234567890 LLтипа unsigned long long int - 1234567890 ULLтипа float - 1.234567 f В противном случае вот здесь константа в формате double может подставляться и вас спасаетвыручает только то, что float и double в вашем компиляторе одинаковой размерности (32 бита). 1. Результат проверил - одинаковый, с точностью до 1 еденицы числа (т.е. если в первом случае 12345678 то во втором и третьем (одинаково) 12345678 или 12345677 - иногда меняеться на 1 еденицу конечный результат - а это +-1 мкВ - меньше чем мзр. АЦП) 2. ImageCraft не требует указания явного обозначения констант, достаточно указать тип переменной и ее значение. (Да и не понимает он таких указаний - я попробывал, препроцессор дает ошибку). 3. Да только в тестовом я так записал константы: реально они пишуться как глобальные константы перед main() - пока ошибок небыло. Код const double Kd=8388608;
Сообщение отредактировал Leonmezon - Jul 27 2009, 17:46
|
|
|
|
|
Jul 27 2009, 18:01
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(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); // Изменяем масштаб и преобразуем в микровольты и возращаем результат
|
|
|
|
|
Jul 27 2009, 20:12
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(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 байта с большей скоростью и тем же результатам (чтоб не переписывать программу на ЭВМ).
Сообщение отредактировал Leonmezon - Jul 27 2009, 20:16
|
|
|
|
|
Jul 27 2009, 20:19
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 28 2009, 00:15)  По сравнению со временем ожидания флага все остальные расходы пренебрежимо малы. Да, но пока я жду флаг - работают другие функции (в первую очередь прием новых данных): т.е. я имею ввиду что, написать функциию так, чтобы время ее выполнения равнялось фактически время ожидание флага умноженое на количество переданных байт (близко конечно).
|
|
|
|
|
Jul 27 2009, 20:26
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(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))); }
|
|
|
|
|
Jul 27 2009, 20:54
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 28 2009, 00:26)  По сравнению с тем временем, что Вы уже отыграли на сокращении вычислений, это 0.
Ну, модифицируйте цикл в передаче, полкопейки может быть выйграете: Нет, выиграша нет (сдвиг на 24 требует почти 200 циклов). А если немного переиначить вопрос: весь проект планируеться перевести на Xmega -в нем за счет DMA возможно будет получить выигреш ? Не сильно меняя при этом логику работы программы.
Причина редактирования: Излишнее цитирование.
|
|
|
|
|
Jul 27 2009, 20:58
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Leonmezon @ Jul 28 2009, 00:54)  Нет, выиграша нет (сдвиг на 24 требует почти 200 циклов). Что-то слабо верится, что компилятор настолько туп. Сдвиг на 24 - это просто взять нужный байт. Или оптимизация выключена? Цитата(Leonmezon @ Jul 28 2009, 00:54)  А если немного переиначить вопрос: весь проект планируеться перевести на Xmega -в нем за счет DMA возможно будет получить выигреш ? Не сильно меняя при этом логику работы программы. Ровным счетом то же самое Вы можете получить и сейчас, если перенесете работу с UART на прерывания.
|
|
|
|
|
Jul 28 2009, 16:01
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Leonmezon @ Jul 27 2009, 23:39)  3. Да только в тестовом я так записал константы: реально они пишуться как глобальные константы перед main() - пока ошибок небыло. Код const double Kd=8388608; Если вы объявляете их как инициализированные константы, то да, указывать не нужно. Т.к. тип этих констант вы уже определили. А вот если бы вы вдруг воспользовались командами препроцессора Код #define Kd 8388608 то грабли бы сработали в полный рост.
|
|
|
|
|
Jul 28 2009, 16:24
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(rezident @ Jul 28 2009, 20:01)  Если вы объявляете их как инициализированные константы, то да, указывать не нужно. Т.к. тип этих констант вы уже определили. А вот если бы вы вдруг воспользовались командами препроцессора Код #define Kd 8388608 то грабли бы сработали в полный рост.  Не сработали  , я не люблю #define - через полгода сам не поймешь что писал. (А выдел я таких писателей - переименовывают названия порта чтоб легче - а потом куча вопросов че да как). Лучше ответить на вопросов - DMA в Xmega может реально ускорить выполнения функции отправки байт (хотя массив с данными и так в ОЗУ находиться) - т.е. делать пересылку автоматом (я запустил и все пока не закончатся). Цитата(aaarrr @ Jul 28 2009, 00:58)  Что-то слабо верится, что компилятор настолько туп. Сдвиг на 24 - это просто взять нужный байт. Или оптимизация выключена?
Ровным счетом то же самое Вы можете получить и сейчас, если перенесете работу с UART на прерывания. Оптимизация выключена (не могу обновить свою версию компилятора на расширенную) - так что нечего удивительного.
Сообщение отредактировал Leonmezon - Jul 28 2009, 16:25
|
|
|
|
|
Jul 28 2009, 16:39
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 28 2009, 20:26)  Выбросьте из процедуры отправки все ожидания флага UART, и подсчитайте симулятором, что останется. Еще раз говорю: это 0, ловить тут абсолютно нечего. Я уже это сделал, но на переключенния задач все равно уходит время, а так его можно было бы уменьшить. И второе: думаю добавить простой цифровой фильтр: (режекторный готов - но он огромен для МК (на первый взгляд): необходимо перемножать массив на матрицу коэффициентов - явно могу не уложиться в 200-300 мс ) и второй - попробовать использовать медианный фильтр (может получиться меньше). Хотя этот вопрос еще требует проработки - какой из двух вариантов имеет наименьшую фазовую нелинейность.
|
|
|
|
|
Jul 28 2009, 16:57
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 28 2009, 20:47)  А может, взять нормальные средства (можно и бесплатные) и, возможно, контроллер помощнее? На AVR и ICC свет клином не сошелся, как это ни странно. AVR не хочеться без нужды менять (тем более я его использую процентов на 20-30), думаю возможностей Xmega должно хватить на простой цифровой фильтр. ICC сейчас меняю на новую версию с оптимизацией (кода и глобальной), но пока ну очень трудно обяснить нашему дистрибьютеру что хочу - у них человек уволился, а нового кто сображает пока нет - радует что еще и макетки не готовы по Xmega.
|
|
|
|
|
Jul 28 2009, 17:35
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(aaarrr @ Jul 28 2009, 21:07)  Поменять AVR на XMega и поменять на что-то другое (дешевле и лучше, ага) - по-моему, принципиальной разницы по трудозатратам нет. Зато есть финансовая разница! (Уже сейчас по Xmega есть все для начала работы (кроме макеток конечно - но я уже писал, это не просто макетка - на ней будет все чтобы сделать готовое изделие (то же направление)). Основным сдерживающим фактором перехода на другой МК - это требования заказчика (по направлению измерения сейсмосигналов) - НИ какой цифровой обработки!!! (Не знаю, согласиться на простой фильтр или нет - а то может зря код оптимизировали). А без цифры - AVR за глаза хватает. Да и переход на Xmega - вообще то довольно таки не трудный (DMA я и так не знаю в любом МК -все равно изучать, а шифрование - мне даром не нужно - специфика применения устройства) - остальные вопросы: АЦП, ЦАП, таймеры, порты, UART, SPI, прерывания, часы .... простые программы уже написал - жду железа чтоб пробовать. А большая часть кода - вообще не будет меняться при переходе.
|
|
|
|
|
Jul 28 2009, 23:47
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Rst7 @ Jul 28 2009, 21:14)  Кстати, адептам целочисленных вычислений хотелось бы напомнить, что правильное умножение float*float практически эквивалентно перемножению long*long. В реализации для процессоров, не имеющих аппаратного деления (AVR в их числе) деление float'ов и long'ов тоже несильно отличается. О(1), не побоимся этого слова. Зато появляется некоторый оверхед на перегнать туда-назад. Цитата(Leonmezon @ Jul 28 2009, 21:35)  Основным сдерживающим фактором перехода на другой МК - это требования заказчика (по направлению измерения сейсмосигналов) - НИ какой цифровой обработки!!! Это, скорее, не сдерживающий фактор  Просто колупаться с обкоцанным ICC - это как-то уж совсем не комильфо.
|
|
|
|
|
Jul 29 2009, 00:18
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(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. Если же имеют место тормоза, проблема не в нехватке ресурса, не в проце и не в компиляторе, а неправильном распределении ресурса. (программа построена неверно).
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|