реклама на сайте
подробности

 
 
> Как передать sprintf() в качестве параметра строку из flash, Перехожу с CV на IAR, help!
Konstantin Ilich...
сообщение Aug 31 2011, 15:54
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 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, которая разбирает спецификаторы.

Посоветуйте, как быть. Может, эта проблема решается совсем просто?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 6)
zhevak
сообщение Aug 31 2011, 16:50
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 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

Главное понять сам принцип, по ходу сориентируетесь сами. Если что -- форумы рулят.
Удачи!


--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
Go to the top of the page
 
+Quote Post
KRS
сообщение Aug 31 2011, 18:50
Сообщение #3


Профессионал
*****

Группа: Модераторы
Сообщений: 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 для строк во флеше.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 31 2011, 19:05
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Konstantin Ilichev @ Aug 31 2011, 18:54) *
Причина - CodeVision рассматривает спецификатор %p как указатель на строку во флеш, а IAR - как *void.
Причина - CodeVision компилятор "языка, похожего на С". В стандарте языка C спецификатор %p предназначен для отображения указателей, а %s - строк. "Строки фо флеш" - вообще чудное расширение архитектуры AVR. В имеющейся у меня документации на ИАР версии 4.хх спецификаторов для строк из флеш не описано.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Konstantin Ilich...
сообщение Aug 31 2011, 20:16
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 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.
Go to the top of the page
 
+Quote Post
zhevak
сообщение Aug 31 2011, 20:26
Сообщение #6


Знающий
****

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



Цитата(KRS @ Sep 1 2011, 00:50) *
С прекрасно подходит и для Гарвардской архитектуры!

Абсолютно с Вами согласен, но с одной оговоркой!

Сам по себе язык С от архитектуры вообще не зависит. Однако, от нее зависит набор тех или иных библиотек. Стандартная библиотека С -- сильно зависит от архитектуры. (Я не захотел делать на этом акцент. Думал, что люди отличают сам язык от его библиотек. А зря наверно!) Как я уже говорил, эта библиотека разрабатывалась применительно к Фон-Неймановской архитектуре. По прошествию нескольких десятков лет с момента появления языка С и его стандартных библиотек (подчеркиваю!) в мире появилось очень много разных архитектур. В том числе и AVR архитектура.

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

CodeVision изначально развивался по своему сценарию и всегда клал болт на стандарты С. Не берусь судить -- хорошо-ли это, плохо ли. Но одно могу сказать -- для новичков он подходит как нельзя лучше. А то, что люди работают с этим (не отвечающим стандартам) компилятором и потом, когда вырастают из этих "коротких штанишек", начинают воспринимать реальные стандарты как отклонение от своего "стандарта CV" -- это так, побочный эффект. Это как с утками -- что первое увидел, которое движется, -- то и мама.


--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
Go to the top of the page
 
+Quote Post
ReAl
сообщение Aug 31 2011, 20:43
Сообщение #7


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



У AVR-GCC проще, там сразу идет %s -- строка в ОЗУ, %S -- строка во флеш


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 27th July 2025 - 03:27
Рейтинг@Mail.ru


Страница сгенерированна за 0.02464 секунд с 7
ELECTRONIX ©2004-2016