Перейти к содержанию
    

лет и ничто не дало мне повод усомниться в EEPROM как именно в памяти.

 

Пожалуйста - простой пример:

 

Прибор время от времени должен спасать некоторые значения

в EEPROM в процессе работы. Которые должны запоминаться.

Это как раз и есть назначение этой области памяти, не так ли ?

 

Итак, спасение началось. Спасаются...ммм.. 10 значений float.

Посто "так надо".

В этот момент пропадает питание..кратковременно.

Срабатывает системный монитор. Например MAX1232.

По достижении питания 4.5 V.

Что получилось ?

Например, первые два значения спасены целиком правильно,

3-е - прописалось частично (первые 2 байта), остальные значения

остались прежними.

 

Пропадание питания было кратковременным. По достижении

питания >4.5 V прибор нормально стартует. И что же в итоге ?

Данные частично новые, частично старые, частично разрушены.

Допустим, речь идет о...новогодней гирлянде. Это не опастно,

просто неприятно - праздник как-никак.

Но в самолет с таким контроллером я добровольно не полезу.

А то какя то вспышка молнии, и автопилот так руль заложит,

что мало не покажется.

:huh:

Получается, что Вам везет.

А мне обычно - не везет. Поэтому я использую эту память

как внешнее устройство.

Замечу, что все эти соображения не относятся именно к AVR.

Это относится к любым EEPROM-ам вообще.

 

Кстати, мне попался процессор с "битым" байтом в области EEPROM.

Данные там стабильно пропадают ~30 мин.

Так вот - прибор с этим процессором работает правильно, и я не стал

его выкусывать.

$3 экономии - пустячок, а приятно.

"Красивый алгоритм - гимнастика ума".

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

-Tумблер-, Вы похоже очень спешите читать пост и в результате читаете не весь. Я говорил о комплексном подходе (...различные hints и recomendations как программистские, так и конструкторские.).

Когда же я столкнулся с проблемой похожей на Вашу (правда не в самолёте, а в газовом хозяйстве, что не умаляет ответственности), где была необходимость "спасать" около 2 кБайт данных, и не в EEPROM, а в DATAFLASH (что более геморройно), то зная это заранее, предусмотрел и особую схему питания с суперконденсаторами и ранним предупреждением, и специальные программные трюки с контрольными суммами, дублированиями и восстановлениями.

И надёжность работы устройства уж никак не зависила от взгляда или отношения к тому или иному ресурсу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 Тумблер:

 

А что в таком случае мешает использовать CRC или прочие алгоритмы контроля целостности данных? И для особо важных данных писать резервные копии?

 

А то, что Вы привели, относится к любым типам памяти, будь то RAM, eeprom или HDD. А не к способу их описания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А что в таком случае мешает использовать CRC или прочие алгоритмы контроля целостности данных? И для особо важных данных писать резервные копии?

 

 

Совершенно верно. Так делаю я - также как и Билли Гейтс.

Делаем резервные копии в количестве N штук. Снабжаем

каждую CRC16. Хочется CRC32, но для avr это все таки затруднительно.

 

Фактически, алгоритм такой же (или очень похожий) как у FAT.

А теперь попробуйте описать это переменной вида:

int my_var;

Конечно, можно попытаться.

Но это черезвычайно не удобно. Эта переменная должна быть удвоена,

утроена и.т.п. Как обратится к ее конкретному образу? :huh:

Или придется описывать класс MY_INT_VAR и перегружать все операции.

Или что-то вроде:

int my_var_1;

int my_var_2; /* где то далеко от _1 - но ГДЕ ? */

...

А потом массив указателей. Что-то это все не красиво.

 

Гораздо легче и понятней:

#define ADDR_MY_VAR 0x.....

 

#define OFFSET1 0x...

#define OFFSET2 0x...

а потом write_eerpom (word addr, byte dat, word offset);

 

byte read_eerpom (word addr, word offset);

 

Все просто, понятно и точно известно - где каждая переменная и

где каждая из таблиц данных (я решил сохранить это определение,

поскольку воспользовался алгоритмом как у FAT)

 

А то, что Вы привели, относится к любым типам памяти, будь то RAM, eeprom или HDD. А не к способу их описания.

 

Мне кажется, вы сами себе противоречите. :)

Уж конечно, описание переменной в RAM сильно отличается от того,

что на HD. То, что на HD вообще как бы и не описывается - туда

доступ "описанием" нельзя обеспечить. К HD можно обратиться, как

к внешнему устройству. И к eeprom я предлагаю обращаться также.

 

Кроме того, RAM с одной стороны и HD, eeprom с другой - существенно

разные памяти по степени "опастности".

Дело в том, что в случае сбоя и после перезапуска RAM обновляется и

все OK. А HD и eeprom запоминают неверный результат и в этом все дело.

Вот и получается, что для работы с ними я выбрал сходные алгоритмы.

По моему, это естественно. На мой взгляд, странно предложить другое.

:)

Применив "FAT-алгоритм" мы вдруг с удивлением обнаружим что:

1. мы можем работать с частично разрушенным физически (навсегда) eeprom

2. мы можем восстанавливать разрушенные (по любым причинам)участки eeprom

3. мы можем не ставить больше системный монитор (экономия $0.5/шт)

4. мы не нуждаемся в средствах бесперебойного питания

5. мы можем наслаждаться красивым алгоритмом который изобрели сами

(увы - мы были не первые, но все-таки)

 

Кстати - "FAT-алгоритм" работает в IBM-PC, да еще как!!!!!

Просто мы не знаем об этом.

Но однажды, когда посыпался мой Fujitsu - 20гб, я вдруг получил

сообщение:

что то вроде: "Обе фат коррупт, не могу починить..."

После этого диск я сдал назад в Техмаркет, а сам стал делать

от 3 до 6 дублей в eeprom

<_<

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Совершенно верно. Так делаю я - также как и Билли Гейтс.

Делаем резервные копии в количестве N штук. Снабжаем

каждую CRC16. Хочется CRC32, но для avr это все таки затруднительно.

 

[...]

 

Или придется описывать класс MY_INT_VAR и перегружать все операции.

А чем не нравится класс?

 

Гораздо легче и понятней:

#define ADDR_MY_VAR 0x.....

 

#define OFFSET1 0x...

#define OFFSET2 0x...

а потом write_eerpom (word addr, byte dat, word offset);

 

byte read_eerpom (word addr,  word offset);

 

Все просто, понятно и точно известно - где каждая переменная и

где каждая из таблиц данных (я решил сохранить это определение,

поскольку воспользовался алгоритмом как у FAT)

 

И чем это лучше? Неслабое нагромождение кода в глобаном scope. В то время как, написав класс, где для вашей переменной объявить массив копий в EEPROM, который и обслуживать:

 

class TMyEEPROM_Var
{
public:
    TMyEEPROM_Var();
    TMyEEPROM_Var(typename x);
    ... // остальной интерфейс

private:
   __eeprom typename CopyArray[N];
};

 

 

Тут уж и проверки сделать при обращениях, и журналирование, и все необходимые операции определить. Т.ч. снаружи это будет просто как обычная переменная. А если уж хочется и отдельные копии смотреть, то и для них функцию определить - типа:

 

typename TMyEEPROM_Var::get_copy(byte intex)
{
    return CopyArray[intex];
}

 

Но обращаться именно в EEPROM посредством __eeprom. Только это будет тоже скрыто внутри класса. А функции явные ee_read, ee_write - это явно излишне. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А чем не нравится класс?

 

Обьясню - чем не нравится класс.

1 Как быть с внешними eeprom-ами ? Концепцию менять каждый раз ?

Вдобавок, в некоторых проектах использовались оба типа.

:huh:

 

2. Использую то я C. Так вышло, мне часто приходится

переходить с процессора на процессор. С с++ бывают

проблемы - например для Fujitsu просто нет.

С переносимостью программ на С проблем (у меня) не было до сих пор.

С пол-оборота всегда и везде все работает.

 

 

А вот теперь серьезно:

3. Если мы озабочены сохранностью данных eeprom,

то делать приходится вот что:

разные таблицы-копии располагаются на разном смещении,

обязательно с "проплешинами" между собой. Чтобы не портились сразу

две таблицы.

Дело в том, что "исследования" показали - когда данные портятся,

то они и расположены рядом. Т.е. портятся смежные байты.

Поэтому совет расположить подряд N копий не кажется мне удачным.

Кроме того, возникнут большие затруднения написания подсчета CRC

в такой концепции.

В предложенном мной варианте известен начальный адрес таблицы

и ее размер. А это значит удобно обратиться к такой таблице как к массиву.

Причем, к любому. Хотите - к байтовому, хотите - к вордовому.

Подсчет CRC дело циклическое и "длительное". Удобство

доступа всерьез повлияет на скорость процедуры.

 

Любое прямое описание переменной в С приводит к ее автоматическому

размещению компилятором. Собственно, это одно из больших достоинств

этого языка. Как раз это, на мой взгляд, и мешает при работе с eeprom.

В этом случае удобно распределить память самому. Это не сложно, поскольку

таких данных сравнительно немного. И это приведет скорей к более компактной

программе - это же к ассемблеру ближе, чем к c++

 

... Неслабое нагромождение кода в глобаном scope. 

 

Извините - я этот вопрос просто не понял . :huh:

Понятно, что я описал идею, а не приводил в конференции

исходных текстов коммерческих программ.

"..Идею дал? - Наморщи ум..".

Я так понял - мы оба согласились сделать "ЭТО", но с разным описанием

переменных. Но это значит, размеры исполнимых кодов у нас

не сильно отличаются. Причем точно известно - дополнительная "оплата"

размером за ооп обязательно будет. Полагаю от 5% - 10 %.

Так что кодов больше будет

у Вас.

Вот исходных текстов может быть больше у меня. Но это мне не тяжко.

Написал отдельный модуль один раз + .def файл макроопределений.

Этот модуль кочует из проекта в проект. Как впрочем и многие другие.

:glare:

Удачи !

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А чем не нравится класс?

 

Обьясню - чем не нравится класс.

1 Как быть с внешними eeprom-ами ? Концепцию менять каждый раз ?

Вдобавок, в некоторых проектах использовались оба типа.

:huh:

 

Какая разница? С внешним все равно не так работаете. И тут можно другую реализацию сделать. Впрочем, это к делу не относится. :)

 

2. Использую то я C. Так вышло, мне часто приходится

переходить с процессора на процессор. С с++ бывают

проблемы - например для Fujitsu просто нет.

С переносимостью программ на С проблем (у меня) не было до сих пор.

С пол-оборота всегда и везде все работает.

 

Да, переносимость - это единственное серьезное возражение, тут спорить не буду. Если она рулит, то деваться некуда. :) Но не удержусь от замечания, что С++ все больше и больше завоевывает позиции, и, как следствие, компиляторов тоже все больше и больше. Причем почти полноценных - с шаблонами, неймспейсами.

 

А вот теперь серьезно:

3. Если мы озабочены сохранностью данных eeprom,

то делать приходится вот что:

разные таблицы-копии располагаются на разном смещении,

[...]

В предложенном мной варианте известен начальный адрес таблицы

и ее размер. А это значит удобно обратиться к такой таблице как к массиву.

Причем, к любому. Хотите - к байтовому, хотите - к вордовому.

Подсчет CRC дело циклическое и "длительное". Удобство

доступа всерьез повлияет на скорость процедуры.

 

Да нет вопросов - хочется располагать со смещением - располагайте. Хочется работать с отдельными байтами - пожалуйста, никто не запрещает. Я не понимаю, как это конфликтует с объявлением переменной с квалификатором __eeprom?

 

Класс-то ведь не в EEPROM живет, он - в обычной памяти. А внутри него забиты адреса данных в EEPROM'е. Просто всю работу он инкапсулирует внутри себя. А данные создаете в EEPROM с помощью слова __eeprom с последующей инициализацией представления класса, где в конструкторе прописываете адреса на EEPROM. При этом нет проблем с созданием многобайтных типов (предположим, Вам понадобилось плавучку в EEPROM хранить или вообще разномастные данные - структуры). И полный статический (т.е. на этапе компиляции) контроль типов.

 

Любое прямое описание переменной в С приводит к ее автоматическому

размещению компилятором. Собственно, это одно из больших достоинств

этого языка. Как раз это, на мой взгляд, и мешает при работе с eeprom.

В этом случае удобно распределить память самому. Это не сложно, поскольку

таких данных сравнительно немного.

 

Ну и распределяйте, никто не возражает. Только почему бы это не делать с помощью __eeprom. Речь о том, чтобы не лазить в EEPROM руками - для этого использовать интерфейсный объект. Но данные разместить (память выделить) отдельно руками, объявив все необходимое с помощью __eeprom, и проинициализировать интерфейсный объект адресами этих данных в EEPROM. Т.е. внутри класса должны быть указатели типа __eeprom typename *. Конструктор объекта должен требовать определенное количество и тип аргументов-адресов - если забудете что-то ему передать, компилятор ругнется. Безопасность использования выше.

 

... Неслабое нагромождение кода в глобаном scope. 

 

Извините - я этот вопрос просто не понял .  :huh:

Понятно, что я описал идею, а не приводил в конференции

исходных текстов коммерческих программ.

"..Идею дал? - Наморщи ум..".

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

 

В случае класса вся работа сокрыта внутри - снаружи как раз простой и формализованный интерфейс - пользователь не видит всего этого внутреннего "ужаса" :), который не "грузит" ему мозги и не провоцирует на ошибки. :)

 

К тому же, можно класс слелать шаблоном и не переписывать все это для разных типов. Один раз написал, и используй для разных типов. __eeprom тут попадает, как говорится, "в струю". :)

 

В общем, не агитирую, по опыту знаю, это дело не нужное, т.к. каждый работает, опираясь на собственный опыт и знания. Но точку зрения изложил, может она послужит поводом где-то и пересмотреть позицию. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Далеко не единственный случай, когда программист не доверяет тому инструменту (компилятору, линкеру), которым пользуется. Причём, под доверием я имею в виду не слепую веру, а точное знание того, как он работает и уверенность в этом.

Мне достаточно часто приходится работать с программистами, которые приходят к C после долгой работы на ассемблере. И едва ли не у каждого из них существует подобная проблема - они теряются от того, что не управляют вручную расположением переменных.

 

Это мне напомнило один случай из жизни: я спросил у одной подруги: "У тебя есть машина, почему же ты не водишь?", на что она мне ответила: "Когда я сажусь за руль, я колёс не вижу".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я не понимаю, как это конфликтует с объявлением переменной с квалификатором __eeprom?

 

Если происходит обьявление __eeprom int value;

то как раз размещением переменных занимается компилятор.

Это как раз мне и не подходит - для данного случая.

 

Но я и не предполагал, что некоторая дискуссия о сохранении

данных в eeprom плавно перейдет в дискуссию о применении ооп... :)

Эти два вопроса совершенно не связаны друг с другом - каждый

сам по себе.

 

Подумав как следует - пришел я к выводу:

можно было бы конечно написать класс. Но не для переменной.

Класс - таблица. С параметром конструктора "TABLEi_OFFSET".

Это еще "куда ни шло". Полагаю в этом случае оплата за ООП

будет минимальной.

А как вы собираетесь считать CRC в вашей концепции ? :glare:

Составлять массив указателей на классы-переменные или

делать связной список из них ? Или разименовывать поочереди ?

:tongue:

 

В случае класса вся работа сокрыта внутри - снаружи как раз простой и формализованный интерфейс - пользователь не видит всего этого внутреннего "ужаса" :), который не "грузит" ему мозги и не провоцирует на ошибки. :)

Да это я знаю.. (ворчливо).

Пользуемся, как же - когда это всерьез выгодно (шас пойдет реклама):

http://spiprog.narod.ru

Извинением мне служит только то, что обращаю ваше внимание

на исходные тексты, а не на что либо иное.

Действительно, ООП в этом конкретном случае дает огромный выигрыш

в производительности труда. И это меня волнует больше всего.

 

Теперь о триллере.

Эпиграф: "..Тебе страшно? Мне-нет...". "Малыш и Карлсон", мультфильм.

 

И где же тут ужас:

my_important_var.save_me_please (); // это у вас

save_my_important_var (); // это у меня.

 

Мне кажется, что ваши "страхи" на программу в 8К

(а на самом деле в 4- инструкции AVR 16-битные)

слегка преувеличены. :blush:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...