Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как заставить помещать строки во флэш?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
prottoss
Всем доброго времени суток!

Столкнулся с такой проблемой: для отладки пользую USART и посылаю собственной функцией usart_print(uchar *str) сообщения вида:

Код
usart_print(("start time at:")
и т.п.

Все бы хорошо, функция отлаженна давно и работает безукоризненно. Но, когда у меня накопилось, в отлаживаемом в данный момент проекте, много сообщений у меня начались глюки в программе выражающиеся, в основном, в том, что программа стала вылетать на reset. После отладки в AVRStudio, оказалось, что добрая часть SRAM заполненна именно моими сообщениями. Установка галки в опциях компилера "Place aggregate initializers in flash memory" ничего не дает. Строки просто дублируются в памяти программ и все. В SRAM они так же присутствуют (((. Конечно, можно все сообщения поместить в отдельные массивы с префиксом __flash, создать еще одну функцию типа usart_print_flash(uchar __flash * str) и делать записи типа
Код
usart_print_flash(msg1)
но это не очень удобно и не очень наглядно. Может быть есть какая то возможность указать компилятору, чтобы динамически создаваемые строки он помещал во флэш, или создавал буфер на лету? ИАР версии 4.10В. Надеюсь, я понятно все объяснил. Спасибо
klop
Я что то не понял. По моему есть два пути
1. Строки хранятся во FLASH, перед употребление копируются в DM, и оттуда используются.
2. Строки хранятся во FLASH и прямо оттуда используются

А какие еще варианты?
prottoss
Цитата(klop @ Nov 3 2006, 03:32) *
Я что то не понял. По моему есть два пути
1. Строки хранятся во FLASH, перед употребление копируются в DM, и оттуда используются.
2. Строки хранятся во FLASH и прямо оттуда используются
А какие еще варианты?
Вы все правильно поняли, я задал вопрос - почему с моей функцией не работает " 1. Строки хранятся во FLASH, перед употребление копируются в DM, и оттуда используются.". Они у меня все в DM получаются...
klop
Цитата(prottoss @ Nov 2 2006, 23:47) *
Цитата(klop @ Nov 3 2006, 03:32) *
Я что то не понял. По моему есть два пути
1. Строки хранятся во FLASH, перед употребление копируются в DM, и оттуда используются.
2. Строки хранятся во FLASH и прямо оттуда используются
А какие еще варианты?
Вы все правильно поняли, я задал вопрос - почему с моей функцией не работает " 1. Строки хранятся во FLASH, перед употребление копируются в DM, и оттуда используются.". Они у меня все в DM получаются...


Хе. Так енто вопросы к компилятору(и языку C). Чтобы не забивать память объявляйте строки во flash, а перед употреблением копируйте их в DM(сами). Не очень красиво конечно но должно работать. Или напишите всетаки функцию которая будет ваши строки прямо из flash выгребать.
prottoss
Цитата(klop @ Nov 3 2006, 04:02) *
Хе. Так енто вопросы к компилятору(и языку C). Чтобы не забивать память объявляйте строки во flash, а перед употреблением копируйте их в DM(сами). Не очень красиво конечно но должно работать. Или напишите всетаки функцию которая будет ваши строки прямо из flash выгребать.
Хе, дак я про то и вопрашаю, есть ли способ заставить компилятор самому создавать константные строки-сообщения во флэш, и забивать их в мою функцию, когда она встречается в тексте программы. Вот такая конструкция, например это делает:
Код
UCHAR msg1[] = "start time at:";

usart_print((msg1)
Строка компилируется во флэш. Но когда встречается объявление msg1, компилятор генерит код, забивающий в msg1 строку из флэш... Хотелось бы чтобы это работало и без объявления msg1...
klop
Цитата(prottoss @ Nov 3 2006, 00:26) *
Хе, дак я про то и вопрашаю, есть ли способ заставить компилятор самому создавать константные строки-сообщения во флэш, и забивать их в мою функцию, когда она встречается в тексте программы. Вот такая конструкция, например это делает:
Код
UCHAR msg1[] = "start time at:";

usart_print((msg1)
Строка компилируется во флэш. Но когда встречается объявление msg1, компилятор генерит код, забивающий в msg1 строку из флэш... Хотелось бы чтобы это работало и без объявления msg1...


Нет в лоб не выйдет. Надо объявлять:
unsigned char __flash MyString[] = "xxx";

и потом либо использовать фукцию выгребающую из flash либо копировать(ручками) в DM.
prottoss
Цитата(klop @ Nov 3 2006, 04:43) *
Нет в лоб не выйдет. Надо объявлять:
unsigned char __flash MyString[] = "xxx";
и потом либо использовать фукцию выгребающую из flash либо копировать(ручками) в DM.
Я же Вам показал, как получается. Если динамически объявляешь массив в памяти данных, и инициализируешь его, то компилятор сам создает в памяти данных ПУСТОЙ масиив, функцию копирования, и данные для инициализации, которые располагает в памяти программ. У Вас есть под рукой AVRStudio и IAR? Вы знаете наверняка, или вам так кажется? Компилятор очень много вещей может делать неявно, на то он и компилятор с языка высокого уровня, а не ассемблер
Andy_F
Может быть, поможет подключение pgmspace ? Т.е., пишем

Код
#include <pgmspace.h>


, в опциях проекта в закладке "C compiler" -> "Extra Options"
ставим птицу "Use command line options"
и набираем строчку --string_literals_in_flash

У меня, правда, получилось не очень. Похоже, если при использовании функций из pgmspace происходит прерывание, то работает это дело некорректно.
prottoss
Цитата(Andy_F @ Nov 3 2006, 05:07) *
Может быть, поможет подключение pgmspace ? Т.е., пишем
Код
#include <pgmspace.h>

, в опциях проекта в закладке "C compiler" -> "Extra Options"
ставим птицу "Use command line options"
и набираем строчку --string_literals_in_flash

У меня, правда, получилось не очень. Похоже, если при использовании функций из pgmspace происходит прерывание, то работает это дело некорректно.
Нет, так не выходит, компилятор сразу вывалил кучу ошибок на все мои строки, типа "Error[Pe167]: argument of type "char __flash *" is incompatible with parameter of type "unsigned char *" E:\AVR.Projects\........... 127 ". Т.е. он все мои строки привратил char __flash и указатели подставляет в мою функцию, а ей надо просто char* ... наверное, придется создать еще одну с указателем на char __flash * (((
IgorKossak
Вобщем то ключевые слова signed и unsigned обычно применяются к обьектам, содержащим по смыслу числовые значения.
Что же касается символьных обьектов и строк на их основе, то общепринятым типом в этом случае является просто char.
Поэтому и обьявления в pgmspace.h вполне оправданные и корректные.
prottoss
Цитата(IgorKossak @ Nov 3 2006, 14:48) *
Вобщем то ключевые слова signed и unsigned обычно применяются к обьектам, содержащим по смыслу числовые значения.
Что же касается символьных обьектов и строк на их основе, то общепринятым типом в этом случае является просто char.
Поэтому и обьявления в pgmspace.h вполне оправданные и корректные.
Ну а по поводу первого моего поста что можете сказать? Есть какие нибудь пути решения, кроме pgmspace?
IgorKossak
Цитата(prottoss @ Nov 3 2006, 09:53) *
Ну а по поводу первого моего поста что можете сказать? Есть какие нибудь пути решения, кроме pgmspace?

pgmspace на мой взгляд - очень приемлемое решение.
Я сам довольно часто (чуть не сказал "всегда") им пользуюсь. Да и зачем писать самому если кто-то уже написал?
prottoss
Цитата(IgorKossak @ Nov 3 2006, 14:57) *
Цитата(prottoss @ Nov 3 2006, 09:53) *

Ну а по поводу первого моего поста что можете сказать? Есть какие нибудь пути решения, кроме pgmspace?

pgmspace на мой взгляд - очень приемлемое решение.
Я сам довольно часто (чуть не сказал "всегда") им пользуюсь. Да и зачем писать самому если кто-то уже написал?
Дело еще вот в чем, на самом деле некторые строки кмпилятор все таки помещает во флэш а некоторые нет... Например все строки, которые в майн и еще в одном модуле он поместил в память данных, а в другом модуле этого же проекта он их засунул в память программ, хотя между первым, вторым и майн ни какой разницы в подключаемых хедерах или еще каком шаманстве нет. По этому то я и обескуражен логикой компилятора! Как он решает, ЧТО поместить во флэш а что в память данных? Естественно, что все строки разные - это сервисные сообщения.

...Полные непонятки (((
IgorKossak
Определяете строки везде одинаково?
Есть разница между:
Код
__flash char My_String[] = "Некий стринг";

и
Код
printf_P("Другой стринг");


Ещё оди нюанс.
Стринг копируется в ОЗУ если, например, функция его использующая предполагает, что он должен быть взят из ОЗУ, а не из flash.
prottoss
Цитата(IgorKossak @ Nov 3 2006, 15:49) *
Определяете строки везде одинаково?
Есть разница между:
Код
__flash char My_String[] = "Некий стринг";

и
Код
printf_P("Другой стринг");
Да нет, вы меня не поняли. Я не подключаю модуль pgmspase. Я пользуюсь своей функцией usart_print(char *string). Так вот, некоторые строки в проекте сидят в памяти программ, и достаются от туда автоматом во временный буфер, который создает САМ КОМПИЛЯТОР, т.е. он сам генерит код копирования и создает в куче буфер. Некоторые же строки он помещает прямиком в память данных, и адреса этих строк подставляет в мою функцию. Вот я и не могу отследить логику его определения, ЧТО пихать в ПП, а что в ПД.

И вот, программа, после очередного usart_print улетает на адрес 0х0000. Главное, что строку она выводит, и после RET идет на RESET. Беда какая то(
andrvisht
Попробовал сделать так
в опциях добавил --string_literals_in_flash
написал функцию типа
Код
foo(char __flash *s)
{
  while (*s++ != 0)
  {
    PORTA = *s;
  }
}

при вызове сделал так
Код
foo((char __flash*)"MyFlash");


вроде как из Flash берет, проверьте, может подойдет ...
sKWO
Добрый всем день! Народ подыму старую тему.
Люди, подскажите, что я делаю не так? переписываю драйвер для ГЖКИ 128х64 с винавра на иар
ИАР для АВР версия 4.21А.
пишу:
Код
#include <pgmspace.h>
....
//основная функция
int main(void) {
               ...
               ...
    LoadBitmap(IMAGE);//////////// ОШИБКА Error[Pe167]
    
}
// функция для загрузки карты
void LoadBitmap(unsigned char *bitmap)
{
  
uint16_t i, j,by;
for(i=0; i<64; i+=8)

        for(j=0; j<128; j++)
        {
            by = printf_P(bitmap++); /////////// ОШИБКА Error[Pe167]
            ks0108GotoXY(j, i);
            ks0108WriteData(by);
        }
}
// и сама карта (массив)
#define LCD_WIDTH 128
const __flash uint8_t IMAGE[] = {
.....
.....
    };

void LoadBitmap(uint8_t *bitmap);

Ну и соответственно и еррор:
Error[Pe167]: argument of type "unsigned char const __flash *" is incompatible with parameter of type "uint8_t *"

В общем на форуме видел сходную ветку : Как заставить помещать строки во флэш
созданную Протоссом, соответственно в опциях проекта в закладке "C compiler" -> "Extra Options"
поставил птицу "Use command line options" и набрал строчку --string_literals_in_flash
НИЧЕГО. В общем IgorKossak знает ответ но чего-то помоему недоговаривает.

Вобщем то ключевые слова signed и unsigned обычно применяются к обьектам, содержащим по смыслу числовые значения.
Что же касается символьных обьектов и строк на их основе, то общепринятым типом в этом случае является просто char.
Поэтому и обьявления в pgmspace.h вполне оправданные и корректные.
Я НХ не понял!!чёто туго
Решил проблему частично так, создал следующую функцию по совету &-rey :
Код
FuncFlash(char __flash *str_)
{
  while (*str_++ != 0);
}

ну и соответственно ее вызов для чтения массива в памяти программ
by = FuncFlash((char __flash*)(bitmap++));

Но с использованием стандартных функций ИАР темно.
теперь выдаёт только одну туже ошибку на LoadBitmap(IMAGE);//////////// ОШИБКА Error[Pe167]
Error[Pe167]: argument of type "char const __flash *" is incompatible with parameter of type "char __flash **"
в общем прикреплю файлы, может кто поможет ? это не горит. Буду признателен по любой информации загрузки (выдачи) массива данных из памяти программ по определённому алгоритму.
Спасибо.
Сергей Борщ
Вы запутались в указателях.
char * - указатель на char
char const * - указатель на константный char.
"Обычный" язык С не знает ничего о флеш, для него cont - всего лишь указание, что данные read-only.
Через указатель на константные данные вы их можете читать. Через обычный указатель - читать и писать. Поэтому вы можете свободно присвоить неконстантный указатель константному - тем самым вы лишь ограничиваете доступ к данным. А вот обратное присвоение запрещено - ибо таким образом вы могли бы полуучить доступ на запись к данным read-only (на самом деле такое присвоение возможно, но лишь с явным приведением типов и оно целиком на совести программиста). Вот компилятор в вашем случае и ругается - вы пытаетесь при помощи указателя получить доступ на запись к константному объекту.
Вам надо прототип функции объявить как FuncFlash(char const __flash *str_), ибо массив, который вы пытаетесь ей передать - константный (const __flash uint8_t IMAGE[] = ....)
sKWO
В общем огромнейшее спасибо Вам, Сергей Борщ!!!!!!!!!
Получилось так:
в хедере Bitmap.h массив карты const __flash char IMAGE[];
в Bitmap.с написал так
Код
FuncFlash(char __flash *str_)
{
  while (*str_++ != 0);
}
void LoadBitmap(char const __flash *bitmap)
{
  
uint16_t i, j,by;
for(i=0; i<64; i+=8)

        for(j=0; j<128; j++)
        {
                   by = FuncFlash((char __flash*)(bitmap++));
                   //by = printf_P(bitmap++);
                   ks0108GotoXY(j, i);
                   ks0108WriteData(by);
                            }

}

Всё работает , даже by = printf_P(bitmap++); не выдаёт ошибку. Правда после 167 ошибки вылезла 27
27 Entry entry in module module (file) redefined in module module (file)
There are two or more entries with the same name. XLINK aborts immediately.
пришлось #include "Bitmap.h" в котором находится массив обявить его как extern ну и прототип функции
соответственно:
Код
Основной модуль программы
//#include "Bitmap.h"

extern void LoadBitmap(char const __flash *bitmap);
extern const __flash char IMAGE[];
int main(void) {
........
........
LoadBitmap(IMAGE);
    while(1);
}

Ну ошибок и нету. Правда проверить на реальном ГЖКИ не могу, нету внутреннего
источника отрицательного напряжения для установки контрассности ну и демоплаты.
Протеус не признаю (люблю "живое" железо) smile.gif

Но непонятки (скрытая тревога) остались. Написал так:
Код
FuncFlash(char const __flash *str_)
{
  while (*str_++ != 0);
}

void LoadBitmap(char const __flash *bitmap)
{
  
uint16_t i, j,by;
for(i=0; i<64; i+=8)

        for(j=0; j<128; j++)
        {
                        by = FuncFlash((char const __flash*)(bitmap++));
                        //by = printf_P(bitmap++);
                        ks0108GotoXY(j, i);
                        ks0108WriteData(by);
                }

}

Появилось предупреждение:
Warning[w6]: Type conflict for external/entry "FuncFlash", in module ks0108 against external/entry in module Bitmap;
function types differ in parameter 1; types have different type attributes
/* In module ks0108: */
/* Function, args 1, attr 0 */
int (__version_3 FuncFlash)(char __flash *);
/* In module Bitmap: */
/* Function, args 1, attr 0 */
int (__version_3 FuncFlash)(char __flash const *);
Сергей Борщ
Цитата(sKWO @ Mar 9 2008, 19:44) *
в хедере Bitmap.h массив карты const __flash char IMAGE[];
Неправильно. Вы определили массив в Bitmap.h, теперь, если вы включите этот файл в два (три, несколько) файла, в которым вам потребуется этот массив, в каждом из этих файлов окажется по копии этого массива, а это явно не то, что вы хотели (даже если не считать того, что все эти копии будут иметь одинаковое имя и линкер не будет знать, какой именно из этих массивов использовать). Вам надо было лишь описать этот массив, чтобы компилятор во всех файлах, использующих этот массив имел возможность сгенерировать правильные команды доступа и проверить правильность использования массива программистом. Итак, поскольку массив у вас констатный, лежит во флеш, состоит из uint8_t, то его так и надо описать: uint8_t const __flash IMAGE[128*8]; Причем собственно "тело" этого массива будет описано в другом файле (наверное в Bitmap.c), поэтому в заголовочном файле его надо описать с квалификатором extern:
Код
#ifndef    BITMAP_H    // "стражи" одного включения должны охватывать весь файл
#define BITMAP_H
//  #include <pgmspace.h>  // ИАР понимает __flash беэ включения этого файла, и никакие функции из pgmspace.h в bitmap.h не используются, поэтому и включать его тут не нужно
#include <stdint.h>    // для использования uint8_t и подобных надо включать stdint.h, а не inttypes.h, и полный путь тоже не нужен - выберите Normal DLIB в Project->Options->General->Library Configuration.

extern uint8_t const __flash IMAGE[128*8];
#endif // BITMAP_H
Соответственно определение массива уходит в Bitmap.c: uint8_t const __flash IMAGE[128*8] = { ....... };
Цитата(sKWO @ Mar 9 2008, 19:44) *
в Bitmap.с написал так
Код
FuncFlash(char __flash *str_)
{
  while (*str_++ != 0);
}
Вы не указали тип возвращаемого функцией значения. Если функция ничего не возвращает, то этот тип должен быть void. Странно, что компилятор молча скушал это и подставил int как возвращаемое значение. Это вылезет боком позже. Ваша функция не изменяет данные, к которым обращается через указатель, поэтому возьмите за правило в таких случаях объявлять указатель в параметрах как указатель на константные данные (не важно, что вы там же указываете __flash). Такой подход имеет два плюса - во-первых не помешает вам передавать в такую функцию указатель на неконстантные данные, а во-вторых компилятор обругает вас и спасет от ошибки, если вы внутри функции все же попытаетесь данные изменить. И вам не придется менять это правило при переходе на любой другой процессор или компилятор, у которого нет ключевого слова __flash. Итого: void FuncFlash(char const __flash *str_).
Цитата(sKWO @ Mar 9 2008, 19:44) *
Код
    by = FuncFlash((char __flash*)(bitmap++));
Вот видите - вы поскупились на const в объявлении функции и вам пришлось делать явное приведение типов. Явное приведение - это первый звоночек о не совсем удачной реализации. А уж "убирание" const через явное приведение типа - вообще удар колокола, такое в программе допустимо только в загрузчике, где действительно надо писать в read-only область.
Цитата(sKWO @ Mar 9 2008, 19:44) *
Правда после 167 ошибки вылезла 27
27 Entry entry in module module (file) redefined in module module (file)
There are two or more entries with the same name. XLINK aborts immediately.
пришлось #include "Bitmap.h" в котором находится массив обявить его как extern ну и прототип функции
соответственно:
Вот-вот. Причем не "пришлось", а так и надо было делать сразу.
Цитата(sKWO @ Mar 9 2008, 19:44) *
Появилось предупреждение:
Warning[w6]: Type conflict for external/entry "FuncFlash", in module ks0108 against external/entry in module Bitmap;
У вас эта функция объявлена в двух местах и объявления эти отличаются. Непонятно, что тут вас смущает - просто сделайте все объявления одинаковыми. Именно поэтому объявления функций, используемых более чем в одном файле выносятся в заголовочные файлы - включая заголовочный файл вы всегда подключаете идентичные объявления.

Покопал ks0108.c - оказывается FuncFlash должна что-то возвращать, причем судя по сравнению с '\0' и '\n' - возвращать должна скорее всего char. А у вас она по умолчанию возвращает int - и вы имеете совершенно лишние операции с двухбайтным данным вместо однобайтного.

Попробовал компилировать исходники - там у вас какая-то путаница из char, const char, uint8_t - приведите их в порядок. char используйте только тогда, когда речь идет о символах. Если этот символ не изменяется функцией - используйте char const. Если речь идет о байте - используйте uint8_t, если этот байт в функции не изменяется - uint8_t const. Поверьте, выработав в себе такую дисциплину, вы сократите время понимания своих же исходников и избежите дурацких ошибок. В качестве проверки можете использовать такую - мне удалось выкинуть все явные приведения типов из вашего исходника.

Еще замечание - в ks0108.c у вас есть строчка #include "iom168.h" - она не совсем корректна. Во-первых, в кавычках указывается имя файла, лежащего в текущей директории. А iom168.h находится в директориях компилятора, поэтому его имя надо указывать в угловых скобках. Во-вторых - точно также как в avr-gcc есть файл <avr/io.h> который сам подключает заголовочный файл для нужного процессора, также и у IAR есть заголовочный файл <ioavr.h>, и включать в проект надо его. Тогда сменив в опциях проекта тип процессора вам не придется лазить по всем исходникам и менять везде заголовочный файл.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.