Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Макросы в IAR EWAVR
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
ivainc1789
В девайсах ATtiny иногда приходится сильно экономить память программ и использовать макросы. Поначалу все получалось и вдруг наступил затык. Три раза проект компилировался нормально, а с четвертого вдруг началась ругань на один из макросов. Причем его строки однотипны, а ругается только с четвертой. Подскажите в чем причина? Использую IAR EWAVR.
Нажмите для просмотра прикрепленного файла
Палыч
Цитата(ivainc1789 @ Feb 8 2010, 09:54) *
Подскажите в чем причина?
Наверное, в том, что между условием после if и else допустим только один оператор.
SasaVitebsk
Цитата(ivainc1789 @ Feb 8 2010, 10:54) *
В девайсах ATtiny иногда приходится сильно экономить память программ и использовать макросы.

Непонятно, как именно вообще макросы могут сэкономить память программ (или вообще какую-нибудь память). И как ваши конкретные макросы её экономят.

1) Макросы - сокращение от макроподстановки. Они могут сэкономить только текст программы. То есть облегчить её написание либо восприятие.
2) Текст программы на Си не то же самое, что результирующий код. Иными словами более короткий текст программы может скомпилироваться в более длинную программу или менее эффективную.
3) Насколько я вижу ваши макросы наоборот сильно расходуют, а не экономят память программ. Хотя - может так задумывалось. Я не уверен, понимаете ли вы разницу в выборе на момент компиляции и на момент исполнения? Дело в том,что независимо от аргумента ваша фича скомпилируется в кучу операторов. Другое дело, что компилятор может часть убрать на этапе оптимизации. Тем не менее можно с помощью тех же макросов сделать запись более наглядной и, препроцессор сгенерит лишь один оператор (или часть).

Ну например:
Код
#if ADC_REFS == REF_VCC
#define ADC_REF_USE (0<<REFS0)
#elif ADC_REFS == REF_EXT
#define ADC_REF_USE (1<<REFS0)
....
#endif

....
....

ADMUX = ADC_REF_USE | TekChanal; // скомпилируется в 2 команды ldi-out
ivainc1789
Цитата
Непонятно, как именно вообще макросы могут сэкономить память программ (или вообще какую-нибудь память). И как ваши конкретные макросы её экономят.
Очень просто. Можно написать макрос как подпрограмму. Например, подпрограмма выбора Vref в ADC на основе всех возможных сочетаний. Это займет значительный кусок кода. Но потом выяснится, что применяется данная программа только один раз для установки Vref = 1v1. Ясное дело, это неэффективно. Если такую задачу решать с помощью макроса, то экономия памяти налицо. Вот почему для многих установок ADC полезно все же писать макросы, но для установки мультиплексора, возможно, подпрограмму (это зависит уже от конкретики задачи)...
Цитата
Дело в том,что независимо от аргумента ваша фича скомпилируется в кучу операторов.
С чего бы это? Какая куча? Скомпилируется только то, что соотв. условию по аргументу...
А посути-то есть что сказать? Если есть желание попробовать, прилагаю код...
Dog Pawlowa
Цитата(ivainc1789 @ Feb 8 2010, 23:03) *
А посути-то есть что сказать?

1) По сути... где фигурные скобки?!
2) Еще раз по сути ... ИАР имеет очень удобную фичу отладки макросов, которая заключается в выводе в файл текста после препроцессора.
3) И третий раз по сути ... Ваши общие рассуждения о расходе памяти программ в случае оформления фрагмента кода как подпрограммы без оговорок о оптимизации и "инлайнирование" неверны. Программист может (и, пожалуй, обязан) написать так, что в любом случае память программ будет расходоваться одинаково экономно.
ivainc1789
Цитата(Dog Pawlowa @ Feb 8 2010, 23:26) *
1) По сути... где фигурные скобки?!
2) Еще раз по сути ... ИАР имеет очень удобную фичу отладки макросов, которая заключается в выводе в файл текста после препроцессора.
3) И третий раз по сути ... Ваши общие рассуждения о расходе памяти программ в случае оформления фрагмента кода как подпрограммы без оговорок о оптимизации и "инлайнирование" неверны. Программист может (и, пожалуй, обязан) написать так, что в любом случае память программ будет расходоваться одинаково экономно.
По всем трем пунктам большое спасибо. Писал все это под утро, уж на автопилоте. Только это что-то мало помогло. Решил упростить все до безобразия и вот... Что же еще упускаю?
Нажмите для просмотра прикрепленного файла

2) если вы про пояснения в листинге, то там то же, что и в окне Build
Цитата
3) Программист может (и, пожалуй, обязан) написать так
То есть вы считаете, что программист заранее ОБЯЗАН знать, что лучше применить макросы или подпрограммы? По-моему, это не так тривиально и возможно только когда окончательно устаканится код... Лично меня как-то все время больше "тянет" на подпрограммы и уже позже, начинаю замечать, что вызовов не так много и возможно макросы отработают лучше...
_Pasha
Пример, заменяющий первую половину использованной Вами ахинеи, место которой вот здесь
Код
#define ADC_REF_VCC 1
#define ADC_REF_EXT  0
#define ADC_REF_1V1  3
#define ADC_REF_2V56 2
#define SET_ADC_CHANNEL(refn, chsel) ADMUX = (refn << REFS0) | (chsel)

Вопрос, а нафига оно нужно, плодить новояз, добавляющий еще один уровень понятий между терминами, определенными производителем микросхем и человеком, читающим текст программы, задавать не буду.
Лучше о хорошем поговорим. Например
Код
#define ADPS_DIV2 1

ни о чем не говорит, а вот с привязкой к F_CPU
Код
#define ADPS_dv(val) ((val >= (F_CPU / 250000)) && (val <= (F_CPU / 50000)))
#if ADPS_dv(2)
#define STD_ADPS 1
#elif ADPS_dv(4)
#define STD_ADPS 2
#elif ADPS_dv(8)
#define STD_ADPS 3
#endif

получаем некоторую свободу от пересчета делителя.
Такие дела.
ivainc1789
Цитата(_Pasha @ Feb 9 2010, 00:21) *
Пример, заменяющий первую половину использованной Вами ахинеи....
Дело не в том, как написано, а в том, что синтаксису это удовлетворяет (теперь), а компилятор выдает ошибку. То, что Вы и прочие специалисты можете написать проще и нагляднее мне совершенно понятно. Могу и я написать. Но почему не работает то, что вроде бы должно?
_Pasha
Цитата(ivainc1789 @ Feb 9 2010, 00:44) *
Но почему не работает то, что вроде бы должно?

Потому что перед отмеченной красным строкой символ "\" не является последним в строке.
SasaVitebsk
Цитата(ivainc1789 @ Feb 9 2010, 01:44) *
То, что Вы и прочие специалисты можете написать проще и нагляднее мне совершенно понятно. Могу и я написать.

Да дело не в простоте и наглядности. И не в красоте. Это все вещи субъективные.

Давайте проведите простой эксперимент. Поставьте свой макрос и выключите оптимизацию. После чего - листинг выложите постом ниже. Вот и будет простой и объективный ответ вам.

Пост ведь называется "макросы". Далее вы указываете "что применяется данная программа только один раз для установки Vref = 1v1". Значит задачу я понимаю правильно. Сами указываете, что "с целью экономии кода".
Подытоживая всё это, как я понимаю надо средствами препроцессора сделать текст проги красивым и наглядным, но, как минимум не в ущерб памяти программ. Сами вы ставите более серьёзную задачу - сэкономить.

На самом деле я вижу, что препроцессор здесь проходит лётом и вся ваша конструкция - достаётся компилятору. Компилятор учитывая что значение условия - есть константа, конечно должен соптимизировать, но простите, вы не упрощаете ему работу, а усложняете.
Именно об этом я и указал.

Проверьте сами и выложите здесь. А то ветка для начинающих, и кто-нибудь из таковых, не разобравшись, вооружится вашими макросами. Да ещё вставит их в CV. А тот уже ему наэкономит будь здоров.
Dog Pawlowa
Цитата(ivainc1789 @ Feb 9 2010, 01:21) *
То есть вы считаете, что программист заранее ОБЯЗАН знать, что лучше применить макросы или подпрограммы?

Ну нет же! Вы воюете с ветряными мельницами, выискивая несуществующую разницу.
Про pragma inline=forced Вы слышали? Она позволяет сделать так, что содержимое функции будет вставлено в текст программы. Потом, после оптимизации Вы получите код, идентичный написанному с использованием макросов.
Все одно, разница только в синтаксисе.
У Вас SETBIT() - это макрос, а у меня SetPin() - это функция, а компилируются они одинаково.
SasaVitebsk
+1.
Не считаю себя профессионалом в данном вопросе, но также хочу отметить один вопрос. Сам его где-то прочитал на форуме - осмыслил - оценил - и теперь стараюсь неукоснительно следовать. Не то чтобы вам советую, просто отмечаю.
Все макроопределения в программе пишу большими буквами. А ф-ции и переменные малыми или смешанными. Это позволяет сразу понять - что есть ф-ция, а что макрос. Для меня - очень удобно.
ivainc1789
Цитата(_Pasha @ Feb 9 2010, 01:14) *
Потому что перед отмеченной красным строкой символ "\" не является последним в строке.
Извините, но не поленился сделать простой проект в IAR. Могу я покорнейше узнать, почему эта ошибка все еще присутствует? У вас компилируется нормально или с той же ошибкой?
Цитата
...выискивая несуществующую разницу. Про pragma inline=forced Вы слышали? У Вас SETBIT() - это макрос, а у меня SetPin() - это функция, а компилируются они одинаково...
Хорошо. Спрошу проще: вы оформили SetPin() как функцию сознательно по каким-либо существенным мотивам или "просто так сложилось"? Т. е. для вас есть существенная разница как написать данную функцию для девайса со всего лишь 4к флеша? Вот что в хелпе нашел:
Цитата
The compiler is capable of inlining functions. This means that instead of calling a
function, the compiler inserts the content of the function at the location where the
function was called. The result is a faster, but often larger, application. Also,
inlining may enable further optimizations. The compiler often inlines small
functions declared static. The use of the #pragma inline directive and the C++
keyword inline gives you fine-grained control, and it is the preferred method
compared to the traditional way of using preprocessor macros.
This feature can be
disabled using the --no_inline command line option.

Но инлайнить нужно не всегда. И, тем более, когда "...это компилер решает...". Т.е. управлять этой прагмой все равно должен пользователь и встает вопрос - не проще ли макрос написать? Почему "gives you fine-grained control" пока не догоняю...
Я не спец по С, прошу уж сильно то не пинать )))), учитывая название раздела для данной темы....
Нажмите для просмотра прикрепленного файла
AHTOXA
Цитата(ivainc1789 @ Feb 9 2010, 20:23) *
Извините, но не поленился сделать простой проект в IAR. Могу я покорнейше узнать, почему эта ошибка все еще присутствует?

Потому что
Цитата(_Pasha @ Feb 9 2010, 03:14) *
Потому что перед отмеченной красным строкой символ "\" не является последним в строке.


Уберите пробел в конце строки
Код
  if (Value == 4)   ADCSRA &= 0x07;else\
ivainc1789
Цитата(AHTOXA @ Feb 9 2010, 18:38) *
Уберите пробел в конце строки
Ок, спасибо! Была установлена опция в IAR IDE Tools/Options/Editor/Enable virtual space, т. е. курсор можно было поставить в любое место строки... а я как-то сразу и не сообразил ))) ...
rezident
На последнем скриншоте из сообщения #13 в макросах нужно убрать завершающий символ "точка с запятой". Потому что этот символ присутствует в тексте программы после "вызова" макросов.
Код
  Simple1(1);
  Simple2(2);
ivainc1789
Цитата(rezident @ Feb 9 2010, 20:26) *
На последнем скриншоте из сообщения #13 в макросах нужно убрать завершающий символ "точка с запятой". Потому что этот символ присутствует в тексте программы после "вызова" макросов.
Код
  Simple1(1);
   Simple2(2);
Верно. Я специально это проверил и с оператором ";" и без. Компилер вроде не ругается и в листинге норма. Или есть какая-то неявная опасность?
rezident
Цитата(ivainc1789 @ Feb 10 2010, 00:09) *
Или есть какая-то неявная опасность?

Точка с запятой является концом оператора. Если она попадет в выражение, то выражение или описание может превратиться в оператор там, где это вовсе не предполагалось.
Пример конечно надуманный, но попробуйте представить, что будет в случае наличия лишнего символа ";" при макроподстановке в цикле for
Код
for (cntr=0; MACRO; cntr++)
{
...
}
Dog Pawlowa
Цитата(ivainc1789 @ Feb 9 2010, 19:23) *
вы оформили SetPin() как функцию сознательно по каким-либо существенным мотивам или "просто так сложилось"?
Т. е. для вас есть существенная разница как написать данную функцию для девайса со всего лишь 4к флеша? ...
не проще ли макрос написать?


1) У меня система описания портов посложнее. Поскольку на одной плате реализовано несколько разноплановых проектов, я поставил задачу определять порты в отдельном файле в виде:
Код
  OUTPUT  (   PulseWdt        ,   A  , 0x01    )
  OUTPUT  (   Backlight       ,   A  , 0x02    )
  OUTPUT  (   EmptyError    ,   A  , 0x04    )
  INPUT    (   SdaIn           ,   B  , 0x01    )

и в общем то решил эту задачу с помощью функций. С макросами как-то не получалось. Не помню уже, почему.

2) если что макрос, что функция занимают одинаково места, то при чем тут размер памяти? Да, без оптимизации моя программа не поместится в память, но я никогда не компилирую без оптимизации. Компилятору нужно доверять.

3) Может и проще, но не такие, как у Вас smile.gif
Писал я подобные макросы. Основной их недостаток - плохая читаемость. А будете работать с тремя-четырьмя семействами контроллеров одновременно, крыша съедет. Мое мнение такое - или макросы должны быть простейшие, или уж система макросов должна надежно поддерживать логичную структуру описания объектов.
От проекта к проекту я так и делаю то одно, то другое, не используя Ваши промежуточные подходы, когда нужно помнить всю эту логику "макросизации".

Эта тема обсуждалась на форуме пару раз, может есть смысл поискать.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.