|
Как передать sprintf() в качестве параметра строку из flash, Перехожу с CV на IAR, help! |
|
|
|
Aug 31 2011, 15:54
|
Участник

Группа: Участник
Сообщений: 62
Регистрация: 7-12-06
Пользователь №: 23 250

|
Добрый день всем! Перехожу с CodeVisionAVR на IAR EWAVR 5.30. При переносе проекта столкнулся с тем, что привычная конструкция компилируется, но не работает: Код sprintf_P(str,"Socket type=%p",(SocketType)?("TCP"):("UDP")); В строке str получается что-то типа такого: "Socket type=3CD". Причина - CodeVision рассматривает спецификатор %p как указатель на строку во флеш, а IAR - как *void. Включена опция "--string_literals_in_flash". В проекте очень много таких конструкций, переделать на %s, мне кажется, нереально. Мне видится, что легче внести изменения в библиотечную функцию sprintf_P, которая разбирает спецификаторы. Посоветуйте, как быть. Может, эта проблема решается совсем просто?
|
|
|
|
|
 |
Ответов
(1 - 6)
|
Aug 31 2011, 16:50
|

Знающий
   
Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065

|
Проблема в том, что Си изначально писался для Фон-Неймановских архитектур, у которых единое адресное пространство для данных и для команд процессора. AVR -же имеет Гарвардскую архитектуру с тремя разными пространствами (RAM, flash, EEPROM). Поэтому, когда Вы используете стандартную (из стандартной библиотеки Си) функцию, например sprintf, и передаете ей в качестве аргументов адреса строк, то функция предполагает, что работает с пространством RAM. Иначе говоря, Ваши строки "Socket type=%p", "TCP" и "UDP" должны располагаться в RAM. Туда они могут попасть только в двух случаях: 1. Автоматически. Такое имеет место быть, когда Вы понятия не имеет о предмете и тупо их прописываете в своей программе(то есть не указываете модификаторы __flash или PROGMEM, в зависимости от компилятора (IAR или gcc)). Так делают все начинающие. У каждого Си-шного проекта по умолчанию имеется файл начальной загрузки или startup-файл. Называется он по разному. Одной из множества его задач является как раз перенос вот таких строк из flash в RAM. Этот способ программирования удобен тем, что не надо думать вообще на эту тему. Недостаток способа -- повышенный расход RAM. Так можно делать, когда у вас проект небольшой, и строковых переменных немного. Перед тем как передать управление в вашу функцию main() загрузчик из всех разом перенесет в RAM. Понятно, что при этом придется отрезать для них нехилый кусок RAM и забыть про него. 2. Ручками. Каждый раз, когда Вам требуется строковая (или любая другая) переменная, которую вы прописали во flash, вы в функции, где она используется, ручками переносите ее в RAM. После того как функция отработает и переменная будет не нужна. Соответствующий объем RAM, временно занимаемый под эту переменную, снова станет доступен для размещения других переменных в других функциях. Иначе говоря, Вы используете RAM по мере необходимости. Вы контролируете процесс. Это и есть преимущество этого метода. Недостаток -- больше возни с исходным кодом, больше заботы, больше нужно уделить внимания техническим деталям -- как это сделать, а не бизнес-задаче, ради которой создавался проект, повышенный расход flash. Когда Вы пишите проект с LCD и меню на какой-нибудь Меге-16, у которой 16 кБ flash и всего 1 кБ RAM, то иногда выгоднее "помучатся", чем вешать дополнительный корпус внешней памяти или устанавливать другой проц, у которого оперативы побольше. Это кому что нравится -- есть профи и есть быдлокодеры. И те, и другие успешно зарабатывают себе на хлеб с икрой. Вот тут я написал, как работать "ручкам" -- http://forum.e-lug.ru/viewtopic.php?id=484 . Описание идет в контексте gcc, но IAR придерживается этих же принципов, поэтому Вы можете смело переносить рекомендации в свой IAR-вский проект. Конечно, Вам придется вместо PROGMEM писать __flash, и ставить модификатор не в конце определения, а в начале. Но принцип работы со строковыми переменными, которые находятся в flash одни и те же. Даже include-файл называется аналогично -- pgmspace.h Главное понять сам принцип, по ходу сориентируетесь сами. Если что -- форумы рулят. Удачи!
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
Aug 31 2011, 18:50
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
Цитата(Konstantin Ilichev @ Aug 31 2011, 19:54)  В проекте очень много таких конструкций, переделать на %s, мне кажется, нереально. Мне видится, что легче внести изменения в библиотечную функцию sprintf_P, которая разбирает спецификаторы. раз надо перенести готовый проект - то логичнее конечно изменить sprintf, но не в самой библиотеке (хотя это тоже можно), а написать свою функцию, за основу конечно можно взять библиотечную - благо исходники все есть. А вообще надо документацию посмотреть может быть у IAR и есть модификатор или тип для указателя на flash (я уже давно с АВР ничего нового не делал) Цитата(zhevak @ Aug 31 2011, 20:50)  Проблема в том, что Си изначально писался для Фон-Неймановских архитектур, у которых единое адресное пространство для данных и для команд процессора. С прекрасно подходит и для Гарвардской архитектуры! И кстати у GCC есть %S для строк во флеше.
|
|
|
|
|
Aug 31 2011, 20:16
|
Участник

Группа: Участник
Сообщений: 62
Регистрация: 7-12-06
Пользователь №: 23 250

|
Всем спасибо за быстрые ответы! Модифицировал функцию, занимающуюся разбором спецификаторов. Получилось просто, всё работает. Далее описываю подробно. 1. Цель - сделать так, чтобы под IAR работал следующий код, написанный для CodeVisionAVR: Код sprintf(str,"Socket type=%p",(SocketType)?("TCP"):("UDP")); Требуется, чтобы в IAR EWAVR код минимально отличался, например, выглядел так: Код sprintf_P(str,"Socket type=%p",(SocketType)?("TCP"):("UDP")); 2. Открываем EWAVR_CompilerReference.pdf, раздел "Overriding library modules", подраздел "Overriding library modules using IAR Embedded Workbench" и далее выполняем пункты из этого подраздела. 3. Создаем в своем проекте папку "mysprintf", в нее копируем файл "frmwri_p.c" (это модуль с функцией _formatted_write_P(), выполняющей разбор спецификаторов и собственно формированием форматированной строки) из папки "src\lib\dlib" (там, где установлен IAR). Модифицируем файл из библиотеки DLIB, так как компилироваться будет именно с ней. Аналогично можно модифицировать файл библиотеки CLIB. 4. В начале файла добавляем строчку, чтобы компилилось с поддержкой float (можно другой дефайн, см. frmwri_p.c). Код #define FLOAT_SUPPORT 5. Вносим требуемые изменения - комментируем стандартную обработку спецификатора 'p' и добавляем свой код: Код case 'p': if ( !(flash_pointer = VAPTR(__flash char)) ) { flash_pointer = null_pointer_str; ptr = buf_pointer=0; ptr += 13; break; } if (precision < 0) precision = 10000; for (n=0; *flash_pointer++ && n < precision; n++) ; buf_pointer = (char *)(--flash_pointer); ptr = buf_pointer; buf_pointer -= n; flash_pointer -= n; break; Этот код сделан на базе обработчика спецификатора 's' (см. frmwri_p.c). 6. Далее изменения в коде для REDUCED_SUPPORT: Код case 'p': ptr_flash = VAPTR(__flash char); while (format_flag = *ptr_flash++) { put_one_char(format_flag, secret_pointer); nr_of_chars++; } continue; Тоже сделано на базе обработчика спецификатора 's'. 7. Больше ничего изменять не требуется, новые переменные не добавляются (используются имеющиеся). 8. Добавляем в свой проект модифицированный файл "mysprintf\frmwri_p.c", имя файла обязательно должно остаться таким же, какое оно в исходной библиотеке. 9. Компилируем, пьем кофе черный, последнее время чай. 10. Хорошая мысль использовать 'S' вместо 'p'. Можно и так сделать. Мне 'p' ни к чему, поэтому оставлю, как в CV.
|
|
|
|
|
Aug 31 2011, 20:26
|

Знающий
   
Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065

|
Цитата(KRS @ Sep 1 2011, 00:50)  С прекрасно подходит и для Гарвардской архитектуры! Абсолютно с Вами согласен, но с одной оговоркой! Сам по себе язык С от архитектуры вообще не зависит. Однако, от нее зависит набор тех или иных библиотек. Стандартная библиотека С -- сильно зависит от архитектуры. (Я не захотел делать на этом акцент. Думал, что люди отличают сам язык от его библиотек. А зря наверно!) Как я уже говорил, эта библиотека разрабатывалась применительно к Фон-Неймановской архитектуре. По прошествию нескольких десятков лет с момента появления языка С и его стандартных библиотек (подчеркиваю!) в мире появилось очень много разных архитектур. В том числе и AVR архитектура. Поскольку стандартные библиотеки С не заточены для работы с Гарвардской архитектурой, то программистам (разработчикам компиляторов) пришлось писать библиотеки функций для работы с флеш-памятью. Теперь, я надеюсь, между нами нет недопонимания  CodeVision изначально развивался по своему сценарию и всегда клал болт на стандарты С. Не берусь судить -- хорошо-ли это, плохо ли. Но одно могу сказать -- для новичков он подходит как нельзя лучше. А то, что люди работают с этим (не отвечающим стандартам) компилятором и потом, когда вырастают из этих "коротких штанишек", начинают воспринимать реальные стандарты как отклонение от своего "стандарта CV" -- это так, побочный эффект. Это как с утками -- что первое увидел, которое движется, -- то и мама.
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|