Возникла необходимость в 2k EEPROM меги64 сохранять коротенькие файлы настроек...
эти файлы настроек разной длинны (поэтому простое сохранение с математическим вычислением адреса в EEPROM) не подходит, а так же необходимо иметь возможность добавлять новые файлы и удалять старые (ну и библиотека должна еще поддерживать наверное функцию дефрагментации)
средний размер файла от 100 до 350 байт
готов обращаться по имени или по номеру (это уже не суть важно) доступ к файлам предпочтителен последовательный побайтный (но в принципе готов и через буфер работать)
подскажите что посмотреть.. или хотя бы где рыть ...
ИМХО - оптимальнее всего будет "типа ФС" по образу и подобию досовской карты памяти приложений: перед каждым блоком данных - небольшой заголовок, в котором (для вашего случая) указывается номер блока, его длинна, + возможно еще что-то (CRC к примеру - на всякий). Следующий блок (вернее, его заголовок) начинается за первым. Удалять - просто метить в заголовке блока номер как FF. Плюсы - весьма малый оверхэд (FAT-подобная ФС к примеру сожрет по самым скромным подсчетам эдак с % 5 еепром при размере "сектора" в 32 байта). Минусы - по мере заполнения/изменения размера "файлов" периодически придется делать "дефрагментацию" - поднимать все в память и записывать на место, упорядочив. Кстати, если не ошибаюсь, подобным образом область еепром в сименсах была реализована...
да, решил применить нечто вроде ФАТ чтобы не иметь проблем при удалении файла.. - чтобы не двигать туда сюда оставшиеся файлы имея при этом максимально возможный размер свободного пространства (тем более что количество перезаписи еепром вроде как ограничено и двигая файлы мы бум расходовать ресурс еепром)..
В итоге сделал по образу и подобию что вы посоветовали но с фиксированной длинной и сократил служебную информацию до минимума.. 1 - номер следующего сектора (поскольку всего 2048 байт в еепроме то секторов всего 2048\32=64 - для хранения номера сектора достаточно одного байта !!, даже для 128ой меги !) 2..32 - данные (31 байт) последний сектор ссылается на FF..
так правда могут быть потери на неиспользованном пространстве в последнем секторе - но я расщедрился и пока решил на них забить
И кстати отпала надобность в процедуре дефрагментации - файлы конечно распыляются постепенно по всему пространству - но ведь у нас не жесткий диск - доступ произвольный - и следовательно быстродействие от распыления не страдает..
как допишу выложу сюда что получилось.. может поправите что (а то у меня с СИ пока не очень хорошо, не берет меня пока Кот с собой на пьянку )
ВитГо, опомнитесь! FAT, сектора - не решение данной задачи. Ну возьмёте, например, готовый fatfs, и это >12кБ flash + >1.5кБ ram минимум! Оно надо? Хотите подобие FAT - сколько её отлаживать будете? Цель в любом случае не оправдает средства.
Какой тип данных нужно сохранить, бинарные или текст? У данных общее что то есть? Выложите пример их или в личку скиньте.
Создаёте typedef структуру с максимально возможным размером. Если данные бинарные, то прописываете имена полей. Если все разные, то union-ом поля объединяете. В коде объявляете массив из этой структуры на сколько eeprom позволяет. Одного байта на заголовок должно хватить. Один байт активна/не активна запись. Не забыть crc16 прикрутить. Всё.
да в принципе ничего страшного нет.. я прикладываю файл который получился...
данные это описание модели передатчика радиоуправляемой моделью.. данные разнородные... в принципе к структуре данных уже написан сериализатор для последовательной записи... данные записываются через fileWrite.. читаются через fileRead... файлов 16, адресуются по номеру... сейчас еще отлаживаю, но код уже работает (мои модели читает и записывает) FAT удобен тем что не нужно ничего двигать.. удалил файл - и у тебя в свободных все возможное пространство.. а то что файлы постепенно будут распределены по всему ЕЕПРОМ - так ведь не жесткий диск - быстродействие не страдает !
p.s. а вот что такое union я пока не освоил (я новичек в Си) может быть есть пример который демонстрирует как это работает ?
Вложения:
Комментарий к файлу: описание модели model_inf.h [5.01 KiB]
Скачиваний: 557
Комментарий к файлу: библиотека диска vdisk.c [7.12 KiB]
Скачиваний: 450
>> а вот что такое union я пока не освоил (я новичек в Си) может быть есть пример который демонстрирует как это работает ?
Информацию легко найти в любом справочнике по С. Привожу, как Вы и просили, пример. Он выдран из одного из проектов, потому на многоточия не смотрите, думаю что для понимания вполне достаточно приведенного фрагмента.
Код:
typedef union tloch {unsigned long lng; unsigned char b[4];} loch; unsigned long shiftdata; unsigned char port, portmask; .... loch storeshiftdata; .... if (inverse){storeshiftdata.lng = ~shiftdata;} else {storeshiftdata.lng = shiftdata;} .... port |= storeshiftdata.b[3] & portmask;
В итоге получится несколько функций: где pos - номер записи в eeprom массиве
Код:
//Отдельная функция проверки записи на активность. char is_ee_active( char pos ); //Проверка записей при включения питания или при сбое. void check_ee_records( void ); //Добавление записи. void add_ee_record( char pos, MODEL_INFO_STRUCT * model_info ); //Удаление записи void del_ee_record( char pos );
Для чтения данных обращение к полю идёт напрямую, зная номер записи.
я бы сделал так... данные (псевдофайлы) записиываются следующими структурами: LEN - длина данных (2 байта) DATA[LEN] - сами данные (любой формат) в EEPROM такие записи пишутся последовательно, т.е. так: {LEN1, DATA1}{LEN2,DATA2}....{LENn=0}, т.е. если поле LEN рано нулю - дальше записей нет. работа с таким псевдодиском ведется следующими функциями: get_data_count - подсчитать число имеющихся записей. начиная с начального адреса EEPROM считывается поле LEN, если оно не ноль, то инкрементируется счетчик записей, вычисляется адрес следующей записи и процесс повторяется. после того, как найдена запись с LEN==0 функция возвращает счетчик. add_data - добавляет очередную запись. сначала по цепочке находит запись с LEN==0, затем определяет, хватит ли места в EEPROM для записи, и, если хватает, пишет запись в конец. если места нет - возвращает код ошибки. обратите внимание: новая запись всегда пишется в хвост цепочки, т.е. в середине "дырок" быть не может. read_data - ну, тут понятно: по номеру записи возвращает данные. write_data - запись данных по номеру - обязательно контролирует длину, чтобы совпадала с выбранным полем LEN! delete_data - удаление записи по ее номеру. все записи, которые существуют ПОСЛЕ удаляемой, сдвигаются к началу, т.е. удаление из середины записи N приводит к тому, что все записи от N+1 до Nmax перемещаются по адресам EEPROM на длину записи N - см. выше: в середине "дырок" быть не может.
получается следующее: при удалении меняется порядок записей, поэтому надо внутри самой записи завести поле, которое бы однозначно идентифицировало бы саму запись - некое имя файла. это может быть просто байт-номер, или целая ASCIIZ строка - дело хозяйское.
следует заметить, что удаление - очень долгий процесс, а так же заметно расходующий ресурс перезаписей EEPROM, но раз вы решили делать псевдо-диск - от этого никуда не деться.
вот такая вот концепция... по-моему, довольно экономичная: накладные расходы порядка 2 байт на запись...
P.S. при перечитывании темы увидел, что идею уже предлагал NiTr0...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
к сожалению не лукавлю ... я неплохо пишу на Delphi (Pascal), наплохо на асме для i8080 (z80), яве (JSP, Servlets), но на СИ никогда ничего не писал... опыт начался буквально месяца 2,5 назад при написании этой прошивки (за это время пробовал перепрыгнуть на асм или паскаль - но в первом не получается даже проинитить дисплей, а второй у меня не работает из за кривого напильника хакера... поэтому пришлось вернуться к СИ Моя проблема что алгоритм я себе представляю достаточно хорошо и подробно.. а вот с реализацией зачастую проблемы... (может быть читали про объявление массива меню flash const menu[] в ветке про CW - которое компилятор упорно кидал в RAM место FLASH - на это убил около недели или вопросы про указатели на переменные и функции.... - синтаксис меня бьет по полной и плюсом еще гарвардская архитектура памяти программ данных и eeprom... - наверное из-за путаницы в ней у меня на асме не инититься дисплей.. а может регистры не те использую... я так и не нашел нормальной книги где бы все это описывалось.. везде "галоппом по европам".. примеры вроде понятные. а начинаешь писать чтото более сложное нежели мигание светодиодами - и начинаются вопросы на которые нет ответов..
asteroid7 писал(а):
ВитГо Увидел одну типовую запись MODEL_INFO_STRUCT. Далее, как бы я делал.
В хидере:
Код:
#define VDISKSIZE 1984 // размер пространства выделенного под виртуальный диск
typedef struct { //активность записи unsigned char active; //0 - не активна //данные MODEL_INFO_STRUCT; //контрольная сумма unsigned int crc16; } TS_EeRecord;
В итоге получится несколько функций: где pos - номер записи в eeprom массиве
Код:
//Отдельная функция проверки записи на активность. char is_ee_active( char pos ); //Проверка записей при включения питания или при сбое. void check_ee_records( void ); //Добавление записи. void add_ee_record( char pos, MODEL_INFO_STRUCT * model_info ); //Удаление записи void del_ee_record( char pos );
Для чтения данных обращение к полю идёт напрямую, зная номер записи.
Нет.. так мне вообще ни на что памяти не хватит структура описания модели имеет размер около 1500 байт !.. при сохранении в файл: части структур CHANNELS, FMODE, MIXER - я сохраняю только если они заполнены... то есть если в модели используется только 4 канала - то и сохраняться будут параметры только первых 4 элементов массивов (а не 16 как в максимуме).. тоже самое с FMODE (от 1 до 3 элементов) MIXER (от 1 до 40)... Структуру в RAМ на полный размер объявляю чтобы удобнее было работать с данными..
Последний раз редактировалось ВитГо Чт июл 08, 2010 09:47:21, всего редактировалось 2 раз(а).
P.S. при перечитывании темы увидел, что идею уже предлагал NiTr0...
Я думал об этом.. но получается что особенно сильно будет расходоваться ресурс первой половины EEPROM.. при редактировании модели - ее размер будет меняться.. поэтому каждое сохранение модели: стерли в текущем месте, сдвинули, записали в конец... - получается что первая половина EEPROM покоя вообще знать не будет... Да и передвижки действительно будут время занимать... сейчас запись 200-300 байт заметна где то почти секундной задержкой (может чуть меньше)... а это будет сначала сдвиг, а потом еще запись... в принципе по времени не страшно.. но вот за ресурс как то переживаю...
с секторами же получается что удаленный файл прицепляется В КОНЕЦ цепочки свободных секторов.. то есть EEPROM будет записываться как бы по кругу.. по кольцу... да и двигать ничего не нужно... потери конечно больше.. намного больше.. 1 байт на заголовок и байт 16 на последний наполовину (не дай бог на четверть) заполненный сектор...
спасибо всем за идеи... пока оставлю то что работает (там еще облизать нужно будет)... на будущее может быть попробую написать второй вариант...
... Нет.. так мне вообще ни на что памяти не хватит структура описания модели имеет размер около 1500 байт !..
Мда... это я поторопился с ответом ( Структура 1410! байт. 0_о как.
Слепок структуры настроек должен храниться в eeprom или это не обязательно? И какова вероятность того, что сохраняемые данные идут последовательно со структурой? Нулевых значений много?
Структуру Вы и так сжали по самое не могу. Наверное ещё несколько байт или десяток сократить можно, но погоды это не делает.
Был у меня и такой вариант: Кольцевая запись по 2 байта с маркером последней. Указатель(байт)-Данные(байт). Указатель сжать до байта - не проблема. Нулевые значения в кольцо не добавляются. Для восстановления настроек обнуляется структура в RAM, пробегается по всему eeprom, от маркера и выше, и по указателям расставляются значения в RAM структуре. Но и при таком варианте все настройки в eeprom не сохранить.
Соглашусь, что подобие файловой системы - более приемлемое решение.
p.s. Не забудьте упаковать (выровнять до байта) структуру. Не знаю Вашего компилятора, но какой нибуть pack() или #pragma pack там должен быть.
Нулевых значений мало.. В принципе у меня сейчас просто сериализатор последовательно выдает данные в файл.. сначала 8 байт имени потом 1 байт тип, потом, например, 1 байт - количество каналов, и после этого подряд данные каналов... и так далее.. нужно только смотреть чтобы порядок чтения и записи совпадали а то можно будет начитать то чего не записывали.. но это не сложная проблема (структуры данных я хорошо проработал и изменений в структуре уже не будет...)
запись "указатель-значение" - не подойдет.. накладные расходы 50%... да и не нужно это когда жестко определена структура считываемых данных...
на счет "упаковки" и "выравнивания" значений - расскажите по подробнее ? компилятор CodeVision
... на счет "упаковки" и "выравнивания" значений - расскажите по подробнее ? компилятор CodeVision
Актуально при копировании/перемещении блоков с указателем "в середину" структуры длиной в байтах. Для Delphi - ключевое слово packed. Для IAR это #pragma pack(1). С CodeVision-ом не знаком. Как в нём выравнивается не подскажу.
Ещё, как вариант сохранения: У Вас mega64. Программа не всю память занимает? Редко изменяемые переменные можно писать прямо во flash. Atmel гарантирует 10.000 перезаписей страницы по 256 байт - против 100.000 eeprom. Если что, ключевые слова в ДШ на контроллер Self-programming.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения