Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: WinAVR & External memory
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Axer
Здравствуйте. У меня проблема с внешней памятью при работе с АтМега64.
Есть программа, рабочая. При подключении внешней памяти начинаются непонятные ошибки, причем ошибки начинаются при выполнении команды memmove() или при выполнении функции вывода строки:
Код
while (*s) ce210_send(*s++);

Вот строчка в мейкфайле, где включаю память, и потом флаги:
Код
EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x8090ff
   ASFLAGS = -Wa,-ahlms=$(<:%.S=lst/%.lst),-gstabs -mmcu=$(MCU)
   CPFLAGS = -MMD -g -O$(OPT) -funsigned-char -funsigned-bitfields -fpack-struct -Wall -Wstrict-prototypes -Wa,-ahlms=$(<:%.c=lst/%.lst) -mmcu=$(MCU) $(CDEFS)
   LDFLAGS = -Wl,-Map=lst/$(TRG).map,--cref, -L$(LIBDIR), $(EXTMEMOPTS) -lm -mmcu=$(MCU)

Вот инициализация в программе:
Код
   setreg(MCUCR, SRE, 1);    // enable external memory (xram)
   setreg(MCUCR, SRW10, 1);                      // configure xram
   XMCRA = _BV(SRW00) | _BV(SRW01) | _BV(SRW11); //

Видно, что проблемы именно с памятью, но вот только где конкретно, не могу понять.
Что не так?
P.S. Версия ВинАВР последняя.
BorisRozentsvaig
Цитата(Axer @ May 24 2005, 12:28)
Здравствуйте. У меня проблема с внешней памятью при работе с АтМега64.
Есть программа, рабочая. При подключении внешней памяти начинаются непонятные ошибки, причем ошибки начинаются при выполнении команды memmove() или при выполнении функции вывода строки:
Код
while (*s) ce210_send(*s++);

*


А каким образом у вас "s" объявлена и инициализирована?

И потом, если s - указатель на массив, то надо смотреть приоритет операторов, может лучше пока написать так:
Код
while (*s)
{
   ce210_send(*s);
   s++;
}


Про приоритет операторов можно посмотреть тут:
http://cclib.nsu.ru/projects/gnudocs/texts/bogatir/9.html
Axer
Цитата
А каким образом у вас "s" объявлена и инициализирована?


Код
void ce210_print(char *s)
{
   while (*s) ce210_send(*s++);
}

Я совершенно уверен, что дело тут не в приоритетах, как я уже сказал, без внешней памяти все работает правильно.

Да, еще одно наблюдение. При инициализации всей памяти, которая учавствует в memmove(), ошибки вроде исчезают. Шаманство какое-то...
pulsar-17
Возможно проблема в __heap_end=0x8090ff

как я понял, объем Вашей внешней памяти = 32k:
90ffH - 1100H = 7fffH = 32767 с учетом нулевого адреса 32768

У AVRа адресация ОЗУ начинается с адреса 0, следовательно при подключении внешней памяти объемом 32к адреса с 0x0000 по 0x10ff будут адресоваться как внутренние, а конец памяти будет = 0x7fff а не 0x90ff. Если Ваш указатель попадал на область выше 0x7fff то обращение шло в никуда, оттуда и могли возникать ошибки.

Это замечание справедливо если у вас нет конвертора адреса, который Ваш 0x1100 на шине адреса AVR преобрезует в 0x0000 на шине адреса ОЗУ.
Axer
Нет, не в этом дело sad.gif
Да и не мог указатель так далеко забраться, я памяти мало использую.
BorisRozentsvaig
Цитата(Axer @ May 24 2005, 14:37)
Нет, не в этом дело sad.gif
Да и не мог указатель так далеко забраться, я памяти мало использую.
*


Вы не ответили на вопрос: каким образом у вас "s" объявлена и инициализирована?

Какую внешнюю память вы используете?

Кстати, я в своем проекте (правда, у меня ATmega128), вообще никаких
-Tdata=0x801100,--defsym=__heap_end=0x8090ff не использую, все без этого великолепно работает.
Axer
Цитата
Вы не ответили на вопрос: каким образом у вас "s" объявлена и инициализирована?


Я ответил.
void ce210_print(char *s)
{
while (*s) ce210_send(*s++);
}
это вся функция.

Цитата
Какую внешнюю память вы используете?

Samsung 328А
Цитата
Кстати, я в своем проекте (правда, у меня ATmega128), вообще никаких
-Tdata=0x801100,--defsym=__heap_end=0x8090ff не использую, все без этого великолепно работает.

Попробую так...
BorisRozentsvaig
Цитата(Axer @ May 25 2005, 15:26)
Цитата
Вы не ответили на вопрос: каким образом у вас "s" объявлена и инициализирована?


Я ответил.
void ce210_print(char *s)
{
while (*s) ce210_send(*s++);
}
это вся функция.


Я понимаю, что это вся функция :-) Вы в неё в качестве параметра передаете указатель, который объявлен и инициализирован у вас где-то в основной программе или в другой функции. Про объявление и инициализацию этого указателя я у вас и спрашивал.
Axer
так:
ce210_print("string");
или так:
char* a;
ce210_print(a);
BorisRozentsvaig
Цитата(Axer @ May 25 2005, 16:45)
так:
ce210_print("string");
или так:
char* a;
ce210_print(a);
*


А с чего вы решили, что данные переменные будут размещены во внешней памяти?
Кстати, во втором случае, я не вижу инициализации указателя.
Вот, например, если бы вы написали:
char* a = 0x2000;
то это был бы адрес внешней памяти.

Попробуйте посмотреть здесь:
http://www.avrfreaks.net/index.php?name=PN...ewtopic&t=29499

Там, правда, речь идет о ATmega128, но принципы одинаковые.
Axer
Цитата(BorisRozentsvaig @ May 25 2005, 17:30)
А с чего вы решили, что данные переменные будут размещены во внешней памяти?

А это здесь причем? Во внешней или во внутренней, все равно глючит.
А во внешней вот почему:
EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x8090ff

Цитата
Кстати, во втором случае, я не вижу инициализации указателя.

Подразумевается, что char* a используется для хранения различных строк.

Цитата
Попробуйте посмотреть здесь:
http://www.avrfreaks.net/index.php?name=PN...ewtopic&t=29499
Там, правда, речь идет о ATmega128, но принципы одинаковые.

Да, они практически не отличаются. Читаю.
BorisRozentsvaig
А что, если вам попробовать запустить для начала тест внешней памяти/
Например, так:

#define EXT_MEM_START 0x1100

BOOL ram_test(void)
{
unsigned short j;

for (j = 0; j < RAM_SIZE; j++) _SFR_MEM8((j) + EXT_MEM_START) = (unsigned char)(j);

for (j = 0; j < RAM_SIZE; j++)
{
if (_SFR_MEM8((j) + EXT_MEM_START) != (unsigned char)(j)) return FALSE;
}
return TRUE;
}
Axer
Сделал тест памяти. Все работает.
С указателями ситуация так и не ясна. Когда он во встроенной памяти - все работает. Как только во внешнюю его помещаю, начинается ерунда.
BorisRozentsvaig
Цитата(Axer @ Jun 1 2005, 13:47)
Сделал тест памяти. Все работает.
С указателями ситуация так и не ясна. Когда он во встроенной памяти - все работает. Как только во внешнюю его помещаю, начинается ерунда.
*


Это хорошо, что тест памяти работает - значит дело не в оборудовании, уже легче.

А попробуйте объявить указатель след. образом:

void ce210_print(volatile char *s)
{
while (*s) ce210_send(*s++);
}

или:

void ce210_print(char *s)
{
volatile char* a = s;
while (*a) ce210_send(*a++);
}

Думаю, что все заработает сразу smile.gif
pulsar-17
можно и без volatile:

void ce210_print(char *s)
{
register char ch;

while (1)
{
ch = *s;
if (ch == 0) break; //(или return)
ce210_send(ch);
s++;
}
}

при while (*a) ce210_send(*a++); да еще и volatile будет скорее всего 2 обращения к памяти, что в данном случае бессмысленно
BorisRozentsvaig
Цитата(pulsar-17 @ Jun 3 2005, 15:18)
можно и без volatile:

void ce210_print(char *s)
{
  register char ch;

   while (1)
     {
        ch = *s;
        if (ch == 0) break; //(или return)
        ce210_send(ch);
        s++;
     }
}

при while (*a) ce210_send(*a++); да еще и volatile будет скорее всего 2 обращения к памяти, что в данном случае бессмысленно
*


Через register тоже можно, не спорю. Но в данном случае главное не скорость, а чтобы заработало :-)
volatile - это для общности.... smile.gif
pulsar-17
Цитата(BorisRozentsvaig @ Jun 3 2005, 16:19)
Через register тоже можно, не спорю. Но в данном случае главное не скорость, а чтобы заработало :-)
volatile - это для общности.... smile.gif
*


Согласен, но мой вариант более предсказуем с точки зрения компилятора (GCC). И в дизассемблере с ним проще разобраться.

Axer, дизассемблируйте Ващу функцию и посмотрите чего там скомпилилос. Я неоднократно нарывался на "неправильный код"(сам был виноват), т.к. GCC очень требователен к конструкциям языка.
Проверьте, какое значение указателя записывается перед вызовом функции и
что находится по этому указателю.
Да и стоит ли на текстовые сообщения ОЗУ тратить? У меня они только во флеше сидят.
#include <avr\io.h>
#include <avr\pgmspace.h>

const prog_char str[] = "test message";

void print(const prog_char *s)
{
char ch;

while(1)
{
ch = pgm_read_byte(s);
if (ch == 0) break;
PORTA = ch;
s++;
}
}

int main (void)
{

print(str);

print(PSTR("TEST2"));//или так

return 0;
}
Dimy
Поднимаю тему, чтобы не плодить новых.

Задача:
- разместить в XRAM несколько длинных массивы, оставив все остальное во внутренней RAM

Во внутренней памяти все работает.

Что делаю:
1)
- в оболочке WinAVR указываю доп. сегмент .xdata 0x802000
- переопределяю размещение массивов (размерность сокращена)
volatile UCHAR BufAdc[281] __attribute__ ((section (".xdata")));
volatile UINT BufAdc1[281] __attribute__ ((section (".xdata")));
volatile UINT BufAdc2[281] __attribute__ ((section (".xdata")));
- разрешаю работу XRAM (тайменги и конфиг. XRAM сути не меняют, но привожу)
MCUCR = (1<<SRE) | (0<<SRW10);
XMCRA = (0<<SRL2) | (0<<SRL1) | (0<<SRL0) | (0<<SRW01) | (0<<SRW00) | (0<<SRW11);
XMCRB = (0<<XMBK) | (0<<XMM2) | (0<<XMM1) | (0<<XMM0);
Размещение:
.xdata 0x00802000 0x57d Variables.o
0x00802000 BufAdc
0x00802119 BufAdc1
0x0080234b BufAdc2

Это работает!

2)
Увеличиваю размерность одного массива до нужного (в *.h как extern естественно тоже), остальное без изменений.
volatile UCHAR BufAdc[1281] __attribute__ ((section (".xdata")));
Размещение:
.xdata 0x00802000 0x965 variables.o
0x00802000 BufAdc
0x00802501 BufAdc1
0x00802733 BufAdc2

Не работает, точнее слетает связь по UART!
Смотрю по map - все остальные переменные находятся на своих местах, т.е. не менялись...
Эти массивы в работе UART при ответах естественно не участвуют.
Возвращаю размер на обратно - работает!

В чем мой косяк?
Прошу пнуть в нужном направлении.

(Mega128A + SRAM, WinAVR + AVR Studio 4.18)

Dimy
Странно,
портится глобальный флаг готовности буфера приема объявленный как
volatile uint8_t fCmdComplite = 0;

прерывание его выставляет = "1", но где то он портится в "0" и в main() он уже "0"...
- свои "сбросы" этого флага убрал...
- его положение сместил в .bss
0x00800248 fCmdComplite

... один ---, т.е. не помогает..

(оптимизация Os)

.... (в 12:15)

Похоже это косяки WinAVR:
при оптимизации -О2 удалось "довести" массивы до 768 единиц!

Шаманство какое-то!!!

Кто нибудь знает как с ним бороться?

..... (18:06)
нет все таки, ряд глюков остался...
наверняка у меня где-то косяк в коде...

кто нибудь знает:
WinAVR при различной оптимизации может валидный код "убивать"?
для IAR, Keil и ICC, что то я таких проблем не припомню...

Dimy
В общем проблемма решена.

Для тех кто наступит на те же грабли:
наплюйте на настройки WinAVR через оболочку (Project/Configeration Options)
просто пользуйтесь внешним Makefile с правками по рекомендации:
http://www.avrfreaks.net/index.php?name=PN...ght=winavr+xram


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