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

 
 
> как узнать в программе последний адрес этой программы (WinAVR)
injen-d
сообщение Apr 8 2008, 18:46
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250



Пользую WinAVR-20071221. Возникла необходимость подсчитывать контрольную сумму программы, но не получается из самой программы узнать до куда, собственно, считать.
Думаю, нужно посчитать до адреса _еtext + длинна(.data), но реализовать это чет пока никак не получается. Должно же быть простое решение? Поиск пока ничего вразумительного не дал.
Наставьте, пожалуста, на путь истиный.
ЗЫ: на асме это делалось элементарно... crying.gif
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
injen-d
сообщение Apr 9 2008, 16:43
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250



Цитата
Как советует zltigo, храните в заранее оговоренном месте в начале программы (например, сразу после векторов) адрес, по которому расположена контрольная сумма.

Не, контрольную сумму (КС) храню в EEPROM, а адрес КС в EEPROM -- простая константа.
Цитата
объявляете в скрипте линкера, в самом конце раздела SECTIONS фиктивный кусочек выходной секции .text (чтобы он разместился после уже заполненной .text и инициализирующих значений .data), объявляете в нем символ и присваиваете ему значение текущего адреса

Попробовал, не подходит. В этом случае _app_end у меня всегда равно уже существующей _etext.
Цитата
а в программе объявляете фиктивную внешнюю переменную с таким именем и берете ее адрес.

А как правильно объявить? Какого она должна быть типа? У меня в итоге получилось, но как-то "через одно место" это работает, но работает правильно.
Цитата
(injen-d @ Apr 8 2008, 21:46) ЗЫ: на асме это делалось элементарно... Можно пример?

_Pasha Вам ответил, это банальная метка в конце программы.

Цитата
А чем плохо CRC всего набортного флеша (либо до boot - секции) ?

Пока хватает простого побайтового суммирования по модулю 256 или 65536, по вкусу.
И зачем контролировать неиспользуемые байты? При порче хоть одного из них, программа начнет бить ложную тревогу, оставаясь при этом полностью работоспособной. А вдруг это (порча) случится
"на самом интересном" biggrin.gif

Как я уже сказал, _app_end у меня всегда равно уже существующей _etext, а _edata = (0x100 + количество инициализируемых переменных (при выравнивании, еще +1))
девайс - ATmega645;
По hex-файлу убедился, что _etext меньше адреса последнего записываемого во флеш байта как раз на количество инициализируемых переменных(ес-но "байтовость" переменных тоже учел),
таким образом объявляем в скрипте линкера в самом конце:
Код
          ......
  _size_prog = _etext +(_edata -0x100);
}

далее используем в функции подсчета.

Привожу свою функцию, может кому будет интересно. В железе пока не проверял, за его отсутствием, но данный алгоритм (реализованный на асме) успешно работает в других готовых девайсах.

Как надо объявлять в функции переменную _size_prog, на сколько я убедился - без разницы, но есть важная особенность: переменная _size_prog не содержит ничего, а вот ее адрес и есть адрес последнего байта, записываемого во флеш.
При попытке использовать _size_prog как есть, компилятор генерит код, пытающийся загрузить значение из ОЗУ с адреса последнего используемого байта во флеш!

Код
//===================================================================
//Функция считает побайтовою сумму flash-памяти с 0 по последний используемый байт;
//Контрольная сумма (КС) хранится в EEPROM;
//Если в EEPROM имеется достоверная КС (байт в EEPROM по адресу f_ee_summ равен 0xAE), то сравнение,
//если нет (первое включение МК после программирования), то запись в EEPROM подсчитанной суммы и
//значения 0xAE по адресу f_ee_summ, затем рекурсивный вызов самой себя;
//Возвращаемое значение: 0 - норма, 0x12 - код ошибки "Ошибка контрольной суммы памяти программ";
#define ee_summ     0x40  //адрес расположения в EEPROM контрольной суммы
#define f_ee_summ     0x30  //адрес в EEPROM флага наличия посчитанной контрольной суммы
extern const uint8_t  _size_prog; //переменная _size_prog должна быть определена в скрипте линкера,
                      //в конце SECTIONS, следующим образом: _size_prog =_etext +(_edata-0x100);  uint8_t summ_flash(void)
{
    uint16_t  summ = 0;
    uint16_t  adr  = 0;
    uint8_t    f_err;
    do
    {
      summ += (uint16_t)pgm_read_byte(adr);   //побайтовое суммирование; сумма 16-битовая
      adr++;
    } while (adr < (const uint16_t)(&_size_prog)+1); //пока адрес меньше, чем (последний байт во Flash)+1
    if (eeprom_read_byte((uint8_t*)f_ee_summ)==0xAE)  //если имеется посчитанная сумма
    {
      if (eeprom_read_word((uint16_t*)ee_summ) != summ)     //если контрольная сумма не совпала-
            f_err = 0x12;                          // - вернуть код ошибки,
            else     f_err = 0;                    // иначе - 0;
    }
    else            //если посчитанной суммы нет (первое включение МК после программирования)
    {
      eeprom_write_word((uint16_t*)ee_summ, summ); //запись подсчитанной суммы
      eeprom_write_byte((uint8_t*)f_ee_summ, 0xAE);  //запись флага наличия достоверной суммы
      while(EECR & (1<<EEWE));                     //ждать окончания записи в EEPROM
      f_err = summ_flash();
    }
    return f_err;
}
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 9 2008, 18:20
Сообщение #3


Гуру
******

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



Цитата(injen-d @ Apr 9 2008, 19:43) *
Не, контрольную сумму (КС) храню в EEPROM, а адрес КС в EEPROM -- простая константа.
А смысл? Почему не хранить ее прямо во флеше, в конце прошивки? Тогда вероятность ее порчи будет такая же, как и для остальных байтов прошивки.
Цитата(injen-d @ Apr 9 2008, 19:43) *
Попробовал, не подходит. В этом случае _app_end у меня всегда равно уже существующей _etext.
Возможно, вы вставили ее не в самый конец, а до объявления секции .data? Я перед написанием того ответа специально поробовал, проходит (правда пробовал на arm-elf-gcc). И у меня скрипт несколько отличается от скриптов из комплекта avr-libc. Вместо ручного подсчета размеров и принудительного задания адресов
Код
  .data      : AT (ADDR (.text) + SIZEOF (.text))
  {
      ......
  }  > data
  .bss  SIZEOF(.data) + ADDR(.data) :
  {
      .......
  }  > data
я даю возможность линкеру самому все это считать:
Код
.data :
  {
      .......
  }  > data AT > text
  .bss :
  {
      .......
  }  > data

Цитата(injen-d @ Apr 9 2008, 19:43) *
А как правильно объявить? Какого она должна быть типа? У меня в итоге получилось, но как-то "через одно место" это работает, но работает правильно.
да любого типа. Вас же интересует ее адрес. Если вы сумируете память побайтно, то и ее разумно объявить байтом, чтобы получился указатель на байт.
Цитата(injen-d @ Apr 9 2008, 19:43) *
_Pasha Вам ответил, это банальная метка в конце программы.
У меня тоже получилась банальная метка _app_end в конце программы. А если программа состоит из нескольких отдельно компилируемых файлов, то без скрипта линкера не обойтись, будь она на ассемблере или С.


--------------------
На любой вопрос даю любой ответ
"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



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

 


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


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