|
Хранение указателя на конец данных в AT45xx DataFlash, Как лучше организовать? |
|
|
|
Jan 21 2008, 11:21
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата Вариант с пустым сектором как маркером конца мне тоже не нравится - потому что придется записи сохранять по границе сектора (ну а запись может быть чуть больше половины сектора - какой овехед получается) и опять же никто не гарантирует что не пропадет питание... Вы видимо не совсем поняли идею. Запись организовывается примерно так Код WritePointer - номер записи WriteSector - номер сектора для записи WritePos - позиция в буфере Nrec - количество записей помещающихся в буфер (SectorSize/sizeof(Record)) Record - собственно запись
WriteSector=WritePointer/Nrec; WritePos=(WritePointer%Nrec)*sizeof(Record); //Заполняем буфер устанавливаем адрес записи в буфер, равный 0 i=0; while(i!=WritePos) {SPDR=0xFF;i++;} j=0; while(j<sizeof(Record)) {SPDR=Record[j++];i++;} while(i<PageSize) {SPDR=0xFF;i++;} //Теперь буфер готов для записи страницы, но предварительно проверяем, а не нужно ли сначала очистить следующую if (WritePos==(SectorSize-sizeof(Record)) { ErasePage((WriteSector+1)%MaxSectors); ErasePage((WriteSector+2)%MaxSectors); } WriteSectorWithoutErase(WriteSector); WritePointer=(WritePointer+1)%(MaxSectors*Nrec); Теперь при старте необходимо искать подряд сначала полностью пустой сектор , потом непустой (это будет голова), потом пустой (предыдущий будет хвостом). Причем, если при поиске дошел до MaxSectors, то продолжать поиск с 0.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Jan 21 2008, 11:46
|
Участник

Группа: Участник
Сообщений: 44
Регистрация: 30-03-06
Пользователь №: 15 598

|
Цитата(Rst7 @ Jan 21 2008, 15:21)  Вы видимо не совсем поняли идею. Запись организовывается примерно так Код WritePointer - номер записи WriteSector - номер сектора для записи WritePos - позиция в буфере Nrec - количество записей помещающихся в буфер (SectorSize/sizeof(Record)) Record - собственно запись
WriteSector=WritePointer/Nrec; WritePos=(WritePointer%Nrec)*sizeof(Record); //Заполняем буфер устанавливаем адрес записи в буфер, равный 0 i=0; while(i!=WritePos) {SPDR=0xFF;i++;} j=0; while(j<sizeof(Record)) {SPDR=Record[j++];i++;} while(i<PageSize) {SPDR=0xFF;i++;} //Теперь буфер готов для записи страницы, но предварительно проверяем, а не нужно ли сначала очистить следующую if (WritePos==(SectorSize-sizeof(Record)) { ErasePage((WriteSector+1)%MaxSectors); ErasePage((WriteSector+2)%MaxSectors); } WriteSectorWithoutErase(WriteSector); WritePointer=(WritePointer+1)%(MaxSectors*Nrec); Теперь при старте необходимо искать подряд сначала полностью пустой сектор , потом непустой (это будет голова), потом пустой (предыдущий будет хвостом). Причем, если при поиске дошел до MaxSectors, то продолжать поиск с 0. А что будет, если ErasePage из-за пропадания питания не выполнится и следующая страница не пустая? ИМХО предложение AlexB более надежное. Кроме того, не нужно деление.
Сообщение отредактировал alcosar - Jan 21 2008, 11:48
|
|
|
|
|
Jan 21 2008, 11:56
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата А что будет, если ErasePage из-за пропадания питания не выполнится и следующая страница не пустая? Если вдруг из-за понижения питания не сработает ErasePage, то дальше дело не пойдет, процессор просто упадет в сброс от BOD'а. Тут конечно, надо процедуру PageErase делать правильную, с тестом, стаботало или нет. И, например, повторять, пока не очистится. Вообщем, такой алгоритм получается вполне транзакционный (если не учитывать то, что самые старые записи могут быть выброшены до записи новой, но это не беда, если это архив событий). Цитата Кроме того, не нужно деление. Если все числа будут кратны 2, то деление и остаток будут преобразованы компилятором в сдвиги и and. Так что тут не волнуйтесь.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Jan 21 2008, 12:03
|

Просто Che
    
Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881

|
Цитата(Alex B._ @ Jan 21 2008, 13:01)  С индексом записи (который в каждой записи и хранится) таких проблем не будет. Когда бы не пропало питание вы всегда сможете найти начало и конец, даже если текущий буфер сектора будет потерян. А алгоритм поиска прост - перебираете все записи, вычисляете CRC, контролируете индексы. Это же сделать надо один раз при включении питания, дальше указатели храняться в ОЗУ Понятно, но я изначально не планировал допускать полного заполнения буфера. В крайнем случае думал ввести маркер конца данных размером с запись. При этом и без индексов записи нет проблем отыскания первой и последней записей при помощи полного перебора всей флешки. Вопрос в придумывании наиболее простого и быстрого алгоритма. Цитата(defunct @ Jan 21 2008, 13:20)  Тем что можно писать в произвольные сектора. Вашу мысль все равно не понял Цитата(Rst7 @ Jan 21 2008, 11:31)  У вас конец буфера маркируется пустым сектором из одних 0xFF. Т.е. реальная емкость буфера колеблется от (N-2)/sizeof(Record) до (N-1)/sizeof(Record) - как минимум, один сектор всегда пустой. Сравнивать конечно с буфером, заполненым 0xFF +1 Вот до этого я уже сам додумался, этот алгоритм мне нравится больше всего. ------------ to All: А другие мысли есть? В EEPROM никто эти указатели не сохраняет?
|
|
|
|
|
Jan 21 2008, 12:37
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Baser @ Jan 21 2008, 15:03)  Вашу мысль все равно не понял ... Вопрос в придумывании наиболее простого и быстрого алгоритма. При каждой записи во флеш увеличивать некий счетчик, записывать в кольцевой буфер внутренней eeprom младший байт этого счетчика (sequence записи), адрес флеш и crc8. После рестарта - вычитать кольцевой буфер в ОЗУ, пробежаться по всем элементам, найти i-й элемент для которого справедливо условие sequence[i] == sequence[i - 1] + 1; sequence[i] != sequence[i + 1] - 1; вытащить из этого элемента адрес флеш. Инициализировать счетчик числом "i + 1". В свете возможных ошибок записи и глюков питания - кольцевых буферов должно быть два. Элементы с неверным CRC должны проверяться из второго буфера. Писать в оба параллельно. Для такого алгоритма есть ограничение на количество записей в кольцевом буфере - записей должно быть строго меньше 256.
|
|
|
|
|
Jan 21 2008, 18:18
|
Участник

Группа: Участник
Сообщений: 36
Регистрация: 4-12-07
Пользователь №: 32 968

|
Цитата(Baser @ Jan 20 2008, 22:59)  Это я прикинул. Почти крайний случай - запись страницы раз в минуту. Год = 365*24*60=525600 минут. За 10 лет = 5.5 млн.записей / 10^5 (ресурс EEPROM)= 55 раз Буфер из 64 указателей выдерживает такую нагрузку. Только вот сразу проблемы с алгоритмом: - Как менять ячейку (по какому алгоритму) - Как запоминать её (указатель на указатель  ) Просто тупо искать среди них самый последний (по величине)?? Где-то был описан простой способ "размазывания" данных по EEPROM (для сохранения ее ресурса): Предположим, нужно "размазать" 1 байт данных, имея массив из 100 байт в EEPROM. Для этого в программе организуем счетчик от 0 до 99, который инкрементируется при каждой записи. В ячейку EEPROM по адресу этого счетчика пишем такое значение, чтобы XOR всех 100 ячеек было равно запоминаемому числу. В итоге максимальное количество записей возрастает в 100 раз. (Если неожиданное отключение питания происходит редко, в качестве начального значения счетчика можно всегда выбирать ноль.) Для защиты от сбоев от выключения питания можно завести несколько таких массивов, например - четыре, и последовательно записывать в них одни и те же данные. При включении питания хотя бы два из них всегда будут одинаковы, и их нужно будет скопировать в оставшиеся.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|