Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Переброс массива из EEPROM в RAM используя указатели
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
SZ0
В поиске был... не могу разобраться с указателями wacko.gif

Есть массив в EEPROM, при запуске проца надо перебросить его в RAM. Написал такой код:

Код
unsigned short *ptr_win, *ptr_win_ee, *ptr_eeprom, g = 0;

ptr_win = (unsigned short *)&win[0];
ptr_win_ee = (unsigned short *)&win_ee[0];

unsigned short size_w = sizeof(win), i = 0; //size_w размер массива в eeprom

while(i < size_w)
{
  EEAR = g++;
  EECR |= (1<<EERE);
  *ptr_win++ = EEDR;
  i++;
}


Не получилось вместо g использовать указатель ptr_win_ee, который указывает на массив в eeprom и присваивать его значение EEAR. И при увеличении указателя *ptr_win++ он увеличивается на два байта, вместо 1. А как его заставить увеличиваться на байт, не могу сообразить cranky.gif
Выручайте, а то голова ваще гудит 07.gif

В таком виде из EEPROM читаются все байты из массива, но пишутся они в RAM через 1 байт. Использование g не правильно, т.к. g инициализировано на начало eeprom. Потому что я заранее знаю где начало массива. А правильно через указание EEAR = *ptr_win_ee++ не получается.
sKWO
Покажите пожалста с каким квалификатором у Вас обьявлен массив
Цитата
win_ee
Sergey Reva
Цитата(SZ0 @ Aug 23 2008, 10:22) *
А как его заставить увеличиваться на байт, не могу сообразить cranky.gif

unsigned short - 16 бит, поэтому на 2 байта увеличивается
SZ0
Цитата(Sergey Reva @ Aug 23 2008, 13:36) *
unsigned short - 16 бит, поэтому на 2 байта увеличивается


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

Цитата(sKWO @ Aug 23 2008, 13:32) *
Покажите пожалста с каким квалификатором у Вас обьявлен массив


В файле описание массивов
Sergey Reva
Цитата(SZ0 @ Aug 23 2008, 10:56) *
Это я понимаю, но вроде как-то возможно заставить увеличиваться на байт.


..
unsigned char *ptr_win;
..
ptr_win = (unsigned char *)&win[0];
...

так годится?
SZ0
Цитата(Sergey Reva @ Aug 23 2008, 14:10) *
..
unsigned char *ptr_win;
..
ptr_win = (unsigned char *)&win[0];
...

так годится?


Верно! А я почему-то твёрдо cranky.gif думал что если так сделаю, для указателя будет использоваться один байт, что не позволит мне обращаться ко всему массиву. Поэтому этот вариант откинул, даже не подумав откомпилить проект sad.gif

А с привильной инициализацией EEAR так и не получается.

EEAR = *ptr_win_ee++; это оказалось не правильно, т.к. EEAR присвивается значение расположенное по адресу ptr_win_ee. (результат писания на не выспавшуюся голову a14.gif )
mempfis_
[quote name='SZ0' date='Aug 23 2008, 11:22' post='458992']
В поиске был... не могу разобраться с указателями wacko.gif

Есть массив в EEPROM, при запуске проца надо перебросить его в RAM. Написал такой код:

Код
unsigned short *ptr_win, *ptr_win_ee, *ptr_eeprom, g = 0;

ptr_win = (unsigned short *)&win[0];
ptr_win_ee = (unsigned short *)&win_ee[0];

unsigned short size_w = sizeof(win), i = 0; //size_w размер массива в eeprom

while(i < size_w)
{
  EEAR = g++;
  EECR |= (1<<EERE);
  *ptr_win++ = EEDR;
  i++;
}


[quote]Не получилось вместо g использовать указатель ptr_win_ee, который указывает на массив в eeprom и присваивать его значение EEAR. И при увеличении указателя *ptr_win++ он увеличивается на два байта, вместо 1. А как его заставить увеличиваться на байт, не могу сообразить cranky.gif
Выручайте, а то голова ваще гудит 07.gif [/quote]

Ва уже сказали что ptr_win_ee и ptr_win указатели на массив данных типа unsigned short - т.е. двухбайтных величин. Указатель в любом случае будет увеличиваться на 2.Хотите увеличиывть на 1 объявляйте массивы как unsigned char. Может быть Вам стоит возложить все обязанности по считыванию данных из еепром на компилятор и использовать например такое:

Код
unsigned short *ptr_win, *ptr_win_ee, *ptr_eeprom, g = 0;

ptr_win = (unsigned short *)&win[0];
ptr_win_ee = (unsigned short *)&win_ee[0];

unsigned short size_w = sizeof(win), i = 0; //size_w размер массива в eeprom
//sizeof(win) возвратит размер массива в байтах

while(i < (size_w/2)) // size_w/2 - кол-во элементов в массиве
{
  *ptr_win++ = *ptr_win_ee++;
  i++;
}
Sergey Reva
Автор, у вас иар? Не знаю тонкостей, но он вроде сам генерит код для доступа к переменным которые объявлены как __eeprom, вы же написали свою процедуру.. mempfis_ предложил использовать стандартные средства, но этот код вроде не сработает, потому что ptr_win_ee = (unsigned short *)&win_ee[0]; убивает(?) квалификатор __eeprom, да и при стандартном иаровском доступе, нету смысла использовать побайтное копирование, достаточно просто обращатся к елементам стуктуры, он (иар) сам добавит нужный код

например
Код
win[0].ADC_sensor[0].A1=2;

уже сразу запишет значение в eeprom
mempfis_
Кстати да ведь можно использовать и запись вида:
Цитата
for(i=0;i < (size_w/2);i++) // size_w/2 - кол-во элементов в массиве
{
ram_massiv[i] = ee_massiv[i];
}


И IAR и CVAVR спокойно воспринимают такие записи и сами вставляют необходимые функции считывания данных их еепром smile.gif главное чтобы массивы были одинакового типа (char, int и т.д)
SZ0
Цитата(mempfis_ @ Aug 23 2008, 14:39) *
Может быть Вам стоит возложить все обязанности по считыванию данных из еепром на компилятор и использовать например такое:

Код
unsigned short *ptr_win, *ptr_win_ee, *ptr_eeprom, g = 0;

ptr_win = (unsigned short *)&win[0];
ptr_win_ee = (unsigned short *)&win_ee[0];

unsigned short size_w = sizeof(win), i = 0; //size_w размер массива в eeprom
//sizeof(win) возвратит размер массива в байтах

while(i < (size_w/2)) // size_w/2 - кол-во элементов в массиве
{
   *ptr_win++ = *ptr_win_ee++;
   i++;
}
}


Забыл сказать что компилятор IAR.

Такую конструкцию я пытался применить, думая что IAR сообразит. Но он лишь "гоняет" так *ptr_win++ = *ptr_win_ee++ байты в RAM, что в принципе верно. Т.к. в указателях адрес. А то что один адрес на еепром указывает, IAR не телепат smile.gif

Применение while(i < (size_w/2)) в таком виде ведёт к лишним затратам, т.к. size_w/2 постоянно обрабатывается в цикле.
Сергей Борщ
Начинать надо с того, что из EEPROM считывание идет побайтно. Значит ваши указатели должны быть указателями на байт. К слову, sizeof() также возвращает размер объекта в байтах. Поскольку исходный массив у вас в словах, надо воспользоваться явным приведением указателей:
Код
unsigned char *ptr_win, *ptr_win_ee, i;

ptr_win = (unsigned char *)win;    // указатель на массив тождественен указателю на его нулевой элемент,
                            // поэтому более короткая запись вместо &win[0]
ptr_win_ee = (unsigned char *)win_ee;

do
{
  EEAR = (unsigned int)(ptr_win_ee++);
  EECR |= (1<<EERE);
  *ptr_win++ = EEDR;
}
while(++i < sizeof(win));  // массив явно ненулевого размера, поэтому используем более эффективный цикл do {} while()
Если компилятор IAR, то все проще:
Код
unsigned char *ptr_win;
__eeprom unsigned char *ptr_win_ee;
unsigned char i = 0;

ptr_win = (unsigned char *)win;
ptr_win_ee = (__eeprom unsigned char *)win_ee;

do
{
  *ptr_win++ = *ptr_win_ee++;
}
while(++i < sizeof(win));

Цитата(SZ0 @ Aug 23 2008, 12:23) *
Т.к. в указателях адрес. А то что один адрес на еепром указывает, IAR не телепат smile.gif
К компилятору обычно должен быть прилажен программист, который четко скажет компилятору, что этот указатель на данные в eeprom smile.gif
Цитата(SZ0 @ Aug 23 2008, 12:23) *
Применение while(i < (size_w/2)) в таком виде ведёт к лишним затратам, т.к. size_w/2 постоянно обрабатывается в цикле.
Так выкиньте лишнюю переменную и используйте в цикле sizeof(win)/2, которое вычисляется на этапе компиляции. Хотя, если включена оптимизация, компилятор должен вынести деление на 2 из цикла даже если size_w передается как параметр в функцию.

А еще эффективнее перейти к циклу do {} while (--i):
Код
ptr_win = (unsigned char *)win;
ptr_win_ee = (__eeprom unsigned char *)win_ee;
unsigned char i = sizeof(win);

do
{
  *ptr_win++ = *ptr_win_ee++;
}
while(--i);
Еще одна уловка: если будете использовать цикл с поэлементным (не побайтным) копированием, то лучше вместо sizeof(win)/2 сразу писать sizeof(win)/sizeof(win[0]) - это позволит не менять исходник этого кода если вдруг придется изменить размер элемента массива.
mempfis_
Цитата(SZ0 @ Aug 23 2008, 13:23) *
Забыл сказать что компилятор IAR.

Такую конструкцию я пытался применить, думая что IAR сообразит. Но он лишь "гоняет" так *ptr_win++ = *ptr_win_ee++ байты в RAM, что в принципе верно. Т.к. в указателях адрес. А то что один адрес на еепром указывает, IAR не телепат smile.gif

Применение while(i < (size_w/2)) в таком виде ведёт к лишним затратам, т.к. size_w/2 постоянно обрабатывается в цикле.

А если не делать приведение типов:
ptr_win = (unsigned short *)&win[0];
ptr_win_ee = (unsigned short *)&win_ee[0];


а просто написать:
Код
[b]
unsigned char *ptr_win;
unsigned char __eeprom *ptr_win_ee;
ptr_win  = &win[0];
ptr_win_ee = &win_ee[0];[/b]

unsihned char size = size_w/2; // чтобы не усложнять жизнь циклу;)

while(i <size) // size_w/2 - кол-во элементов в массиве
{
  *ptr_win++ = *ptr_win_ee++;
  i++;
}




Цитата(mempfis_ @ Aug 23 2008, 13:30) *
А если не делать приведение типов:
ptr_win = (unsigned short *)&win[0];
ptr_win_ee = (unsigned short *)&win_ee[0];


а просто написать:
Код
[b]
unsigned char *ptr_win;
unsigned char __eeprom *ptr_win_ee;
ptr_win  = &win[0];
ptr_win_ee = &win_ee[0];[/b]

unsihned char size = size_w/2; // чтобы не усложнять жизнь циклу;)

while(i <size) // size_w/2 - кол-во элементов в массиве
{
  *ptr_win++ = *ptr_win_ee++;
  i++;
}



проверил у себя в иаре - код работает smile.gif
SZ0
Цитата(Сергей Борщ @ Aug 23 2008, 15:26) *
Начинать надо с того, что из EEPROM считывание идет побайтно...


Спасибо за подробные разъяснения, всё работает. Только здесь __eeprom unsigned char пришлось поменять на unsigned char __eeprom иначе IAR выдаёт ошибку.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.