Страница 25 из 110

Добавлено: Вс фев 28, 2010 21:19:54
Aheir
Ничего не понял. У Вас массив на 32 элемента, соответственно, они нумеруются от 0 до 31. Обращение vol_tda[0] разве не даст 0x1C?
Т.е. если записать a = vol_tda[0], то а станет равным 0x1C...

Добавлено: Вс фев 28, 2010 21:22:33
smac
Alex_NEMO писал(а):...
Вопрос: как мне обратиться к любому элменту массива по индексу а не по содержимому? Через "CASE" сопоставлять содержимое индексу?
Что-то странный у Вас вопрос если есть индекс i то к i-тому элементу обратиться просто vol_tda, хотите прочитать элемент массива в переменную x = vol_tda; если наоборот хотите записать переменную в элемент массива то vol_tda = x;
Как-то так.

Добавлено: Вс фев 28, 2010 21:56:25
Alex_NEMO
Парни, спасибо за ответы, я просто "чайник" и некоторые моменты пока ещё не догоняю! Можно ещё спросить, применительно к "статейному" проекту? А то "родная" тема в Статьях, похоже надолго затихла! Правлю "под себя" проект "MINI-16" http://radiokot.ru/circuit/audio/amplifier/34/, хочу реализовать "плавное"(но, в тоже время, быстое) повышение/понижение громкости при входе/выходе в/из режимы "StandBy" и "Mute". В "оригинале" присутствуют в эти моменты очччень неприятные щелчки звука! Потому хочу добавить пару процедур для плавного уменьшения звука от "текущего" до "минимума" и для плавного увеличения звука от "минимума" до "текущего". С vol_min - понятно, это tda_vol[0]. А как определить tda_curr(текущая)? Текущее значение громкости сохраняется в EEPROM и читается оттуда же в переменную p_tda[VOLUME_MENU]. Вернее, диапазон паременной p_tda[VOLUME_MENU] от 0 до 63, а массив "громкостей" всего 32 ??? Как это скрестить? Чего-то я вообще не могу понять.... Или просто тупо: tda_curr = (p_tda[VOLUME_MENU])/2?

Добавлено: Пн мар 01, 2010 21:45:53
CHYVAK[EASTSIDE]
Подскажите пожалуйста чем отличаются оптимизации и что каждая делает в WINAVR

0
1
2
3
s

???

Объясните, что делает каждый уровень? пожалуйста
Просто говорят в IAR при каком то уровне оптимизации удаляются бесполезные циклы, у меня некторые прои себя ведут не адекватно, вот поэтому думаю не удалет ли у меня некторые циклы компилятор

Добавлено: Пн мар 01, 2010 23:14:50
neonix
Кратко тут явно не объяснить по ключам GCC целые книги есть :)
1) -Os (size) - оптимизация по размеру наиболее оптимальная оптимизация по размеру и скорости кода
2) -O0 фактически полное отсутствие оптимизации, глюков на этом уровне не оберешся, к использованию категорически не рекомендуется.
3) -O1 первый уровень оптимизации недалеко ушел от нулевого
4) -O2 второй уровень оптимизации, должен по логике вещей делать код более быстрым но на AVR его только разносит в размерах и в итоге все работает еще медленнее...
5) -O3 фактически тоже самое что и второй
PS: Для AVR советую всегда оставлять оптимизацию по размеру, такой код и работает шустро и мало весит. И не будет таких тупых глюков, как при отсутствие оптимизации, когда прога будет валиться от простейших вычислений. Более конкретно ищите в гугле, ибо щас и не вспомню какие различия в настройках компилятора для разных оптимизаций.
Или изучайте сами

Код: Выделить всё

avr-gcc --help=optimizers

Добавлено: Вт мар 02, 2010 07:31:13
ARV
сразу хочу сказать, что никаких глюков при отключении оптимизации -O0 быть не может, кроме значительного увеличения объема кода и сильного замедления скорости выполнения (так же программные задержки безбожно врут).

кроме перечисленных "уровней" оптимизации в AVR-GCC имеется еще куча опций, влияющих на оптимизацию, этих опций, наверное, десятка 4. так вот, есть опции, регулирующие способ разбрасывания переменных по регистрам, есть управляющие "разворачиванием" циклов, инлайнингом функций и т.п. Некоторые из этих опций дают увеличение скорости при увеличении объема (разворачивание циклов), другие дают экономию кода при замедлении скорости (например, оформление пролога и эпилога функций в виде отдельных функций). как вы понимаете, разные их комбинации могут давать разные результаты. вот и подобрали 4 комплекта из этой кучи опций, которые автоматически включаются всего единственной опцией -O.

здесь верно говорили, что кроме -Os нет особого смысла использовать прочие варианты: как правило, это наиболее оптимальный вариант и по скорости и по объему. мои эксперименты подтвердили, что цикл, который выполняется за 33148 мкс при компиляции с -Os ускоряется всего до 33106 мкс при опции -O3, зато размер кода увеличивается почти на 18%.

но главное, что вы должны знать: при включенной оптимизации становится очень затруднена отладка пошаговая в студии или протеусе: компилятор так "тасует" код, что порой целые куски кода, который явно полезный, оказываются черт знает где и хрен поймешь, когда исполняется. а вот при выключенной оптимизации каждая строчка исполняется, как положено. поэтому, если у вас неоптимизированная программа влезает в память МК, вы можете отладить логику ее работы при помощи отладчика, а потом включить оптимизацию и собрать компактную и быструю версию.

главное: оптимизатор не портит код! если у вас неоптимизированная и оптимизированная программы работают по-разному (скорость не считается) - это говорит не о глюке оптимизатора, а о том, что вы написали программу безграмотно, с ошибками. только и всего.

Добавлено: Вт мар 02, 2010 10:17:43
Danko
вопрос к AVR:
версии WinAvr от 2010 года компилируют с большей оптимизацией чем версии от 2007 года?

Добавлено: Вт мар 02, 2010 11:16:07
ARV
Danko писал(а):вопрос к AVR:
версии WinAvr от 2010 года компилируют с большей оптимизацией чем версии от 2007 года?
я не пользовался версией за 2007 год, самая первая моя версия - конец 2008. По сравнению с 20090313 лично я не заметил существенного выигрыша в 20100110, однако знающие товарищи утверждают, что на каждые 4-5 килобайт кода новая версия дает примерно 100-200 байт экономии :) все ведь зависит от того, что именно вы там понапишите - одно лучше получается, другое хуже...

правда, есть мнение, что в 20100110 присутствует небольшой глюк, который может попортить кровь при работе с прерываниями, если используется атрибут ISR_NOBLOCK - но это экзотика, в общем-то... я пока не страдаю.

в 2010-й версии сильно переделан модуль работы с EEPROM: появились функции обновления данных (т.е. не перезаписывают, если данные не изменились), а так же запись блока данных теперь намного оптимальнее, чем раньше. поэтому при работе с EEPROM выигрыш в размере кода может быть очень заметен.

Добавлено: Вт мар 02, 2010 13:45:20
AI_Disable
Решил провести для себя небольшой эксперимент: взял 5 первых попавшихся своих проектов и сравнил размеры скомпилированных прошивок на уровне оптимизации Os между WinAVR-20090313 и WinAVR-20100110. В среднем получилось, что последняя версия компилятора делает на 0,52% более компактную прошивку. Ниже приведена сводная таблица. Да, описание прошивки не самое корректное, но обратите внимание на тот факт, что в случаи с мегой32 и кодом ~16кб экономия составила всего 30байт - капля в море при 32кб флэша. Однако в случаи с тини13 и кодом ~1кб экономия составила целых 24 байта! Честно говоря, я даже немного удивился, ведь помню как при написании этой программы я отвоевывал байт за байтом, чтоб уместить всё в 1кб флэша тини13. А тут сбросил столько веса, просто обновив компилятор.
Изображение

Добавлено: Вт мар 02, 2010 14:22:26
ARV
а вы используете "тонкую" оптимизацию?
--param inline-call-cost=X поможет изменить повдение оптимизатора при инлайнинге функций. праметр Х может быть в пределах от 0 до 12, по умолчанию 9. попробуйте подобрать это значение - часто помогает очень заметно.

-fno-split-wide-types поможет вам, если в программе используются рассчеты с числами long или много функций, которые в параметрах имеют типы int или более длинные.

указание для функции main() атрибута OS_main так же даст от 4 до 12 байт экономии, а то и более.

Добавлено: Вт мар 02, 2010 19:31:45
AI_Disable
ARV писал(а):а вы используете "тонкую" оптимизацию?
Нет, увы, знал только об её существовании, до сего момента. Но уже вижу, что это имеет смысл: добавил инлайн функции чтения EEPROM и код на тини13 сократился ещё на 18байт. С остальными пока не разобрался, не покажите как их юзать? Просто уж очень часто бывает, что не хватает 100-200 байт и приходится всяко извращаться.

Добавлено: Вт мар 02, 2010 19:57:34
ARV
да так и использовать - укажите эти опции в командной строке компилятора, и всех делов :)

Добавлено: Вт мар 02, 2010 20:12:56
AI_Disable
Я в студии пишу. В случаи c inline сделал так:

Код: Выделить всё

inline unsigned char EEPROM_read(unsigned char Address)
{
...
}
Насколько я понял, компилятор меня понял :) А вот как другие пользовать до меня не дошло.

Добавлено: Вт мар 02, 2010 20:55:22
ARV
вы поняли не правильно, хотя и получили положительный эффект. в вашем случае во-первых, практичнее пользоваться встроенными функциями для работы с EEPROM из модуля eeprom.h типа
uint8_t eeprom_read_byte(uint8_t *addr);
void eeprom_write_byte(uint8_t *addr, uint8_t data);
и так далее.

во-вторых, для функций, которые требуются только в одном единственном модуле надо указывать префикс static - в вашем случае inline сыграло его роль, но static может помочь больше (может, но может и не помочь).

в-третьих, указанные мною опции следует вводить именно так, как я написал, целиком и без фантазий. вводить их следует в опции компилятора - закладка Custom Options для парамтеров проекта. там их и надо ввести по аналогии к уже имеющимся.

Добавлено: Вт мар 02, 2010 21:56:50
AI_Disable
ARV писал(а):в вашем случае во-первых, практичнее пользоваться встроенными функциями для работы с EEPROM из модуля eeprom.h
Да, я пробовал, итог - лишние 16 байт.

Добавлено: Пт мар 12, 2010 13:14:28
Rusja2008
Здравствуйте форумчане, есть небольшой вопрос. Нужно из флеш памяти вытаскивать слова и отображать их на LCD (HD контроллер).
Я организовал так (куски програмы):

сама запись в память const char *msg_1 PROGMEM="DATA";

вот передача на дисплей:
void lcd_puts_mem(const char *str)
{
while(*str) {lcd_putchar(*str); *str++};
}


суть в том, что если написть:
lcd_puts_mem(pgm_read_word(&msg_1));
программа компилится и в железе работает, но компилятор естественно ругается, что в функцию подставляется не указатель, а число ("making pointer from integer without a cast").

Хочется чтоб все было грамотно, потскажите как это сделать? А то никак не могу найти разумное решение :)

Добавлено: Пт мар 12, 2010 13:46:19
ARV
Rusja2008, вы немного напутали и сделали совсем не то, что задумали.

const char *msg_1 PROGMEM="DATA"; - это объявление во FLASH указателя на строку, а сама строка при этом остается в ОЗУ :))) изучите листинг и вы в этом убедитесь.

и далее вы загружаете из FLASH именно указатель, а символы строки берете из ОЗУ - все это очевидно по вашему коду.

на самом деле, если вам надо выводить строки на дисплей без всякой зауми, то надо сделать так:

Код: Выделить всё

void lcd_puts_P(char *str){
   char c = pgm_read_byte(str++);
   while(c){
      lcd_putchar(c);
      с = pgm_read_byte(str++);
   }
}

lcd_puts_P(PSTR("Привет!"));
то есть для занесения строки во FLASH и одновременно получение адреса ее надо использовать макрос PSTR(x);

Добавлено: Пт мар 12, 2010 14:07:24
Rusja2008
Огромное спасибо ARV, действительно строка сидит в ОЗУ. Наступил на огромные грабли :))
И хочу уточнить: строчка "lcd_puts_P(PSTR("Привет!"));" как раз считывает по адресу в флеш и загоняет на дисплей, а для того чтоб записать строку в память как правильно записать? (PSTR("слово") или не так). Хочу сразу спросить ато WinAVR стоит дома на компе, а я на работе.

Добавлено: Пт мар 12, 2010 14:15:15
ARV
я не совсем понял, что вам надо.

PSTR("Вася"); поместит строку "Вася" во FLASH. макрос PSTR(x) удобно использовать именно в тех случаях, когда надо просто вывести строку при помощи функции, тогда этот макрос используется именно как указатель на строку во FLASH. если же вам просто захотелось сделать во FLASH строку, то это делается элементарно:

Код: Выделить всё

PROGMEM char name[] = "Вася";
если вы посмотрите, как макрос PSTR() устроен, вы увидите то же самое :)

Добавлено: Пт мар 12, 2010 14:24:28
Rusja2008
Все, все - понял, еще раз спасибо. Я напутал способ считывания строки и ее записи. :))