Циклический буфер во Flash

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

Как лучше хранить циклическую очередь во флэш-чипе?

Есть возможность хранить десятки тысяч предметов, которые я хотел бы хранить. Поэтому начинать с начала и читать до конца буфера не идеально, потому что поиск до конца займет время.

Кроме того, поскольку он круглый, мне нужно уметь отличать первый элемент от последнего.

Последняя проблема заключается в том, что это хранится во флэш-памяти, поэтому стирание каждого блока занимает много времени и может быть выполнено только определенное количество раз для каждого блока.


person Robert    schedule 03.11.2009    source источник
comment
Меня смущает ваш язык. Буфер, на мой взгляд, — это быстрая, изменчивая часть памяти, которая часто изменяется. Как вы правильно заметили, у флеш-памяти могут быть некоторые проблемы с этим. Можете ли вы предоставить немного больше контекста или подробностей о том, что вы пытаетесь сделать и почему?   -  person Mikeb    schedule 03.11.2009
comment
Я хочу сохранить данные в энергонезависимой памяти. Энергонезависимая память у меня флешка. Энергонезависимость важна, потому что продукт может быть отключен на некоторое время, и я не хочу терять данные. Когда питание снова включается, ему нужно поместить следующий фрагмент данных после последнего.   -  person Robert    schedule 03.11.2009


Ответы (5)


Во-первых, управление блокировкой:

Поместите меньший заголовок в начале каждого блока. Главное, что вам нужно для отслеживания «самого старого» и «самого нового», — это номер блока, который просто увеличивается по модулю k. k должно быть больше общего количества блоков. В идеале сделайте k меньше вашего максимального значения (например, 0xFFFF), чтобы вы могли легко определить, что является стертым блоком.

При запуске ваш код по очереди считывает заголовки каждого блока и находит первый и последний блоки в последовательности ni+1 = (ni + 1) ПО МОДУЛЮ k. Будьте осторожны, чтобы не запутаться со стертыми блоками (номер блока, например, 0xFFFF) или данными, которые каким-либо образом повреждены (например, неполное стирание).

В каждом блоке

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

Если вы хотите иметь записи переменного размера, но избегаете линейного сканирования, вы можете иметь четко определенный заголовок для каждой записи. Например. используйте 0 в качестве разделителя записи и COBS-encode (или COBS/R-encode ) каждой записи. Или используйте байт по вашему выбору в качестве разделителя и «экранируйте» этот байт, если он встречается в каждой записи (аналогично протокол PPP).

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

Удалить расписание

Для некоторых микросхем флэш-памяти стирание блока может занять значительное время. 5 секунд. Подумайте о том, чтобы запланировать стирание как фоновую задачу немного «заблаговременно». Например. когда текущий блок заполнен на x%, начните стирать следующий блок.

Нумерация записей

Возможно, вы захотите пронумеровать записи. Раньше я делал это так: в заголовке каждого блока помещался номер первой записи. Затем программа должна вести подсчет номеров каждой записи в блоке.

Контрольная сумма или CRC

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

person Craig McQueen    schedule 03.11.2009
comment
Здравствуйте, Крейг МакКуин, не могли бы вы взглянуть на мой вопрос о циклическом буфере во флэш-памяти Циклический буфер в реализации флэш-памяти< /а> - person Steve; 02.01.2019

Сохраните отдельный блок, содержащий указатель на начало первой записи и конец последней записи. Вы также можете сохранить дополнительную информацию, такую ​​как общее количество записей и т. д.

Пока у вас изначально не закончится место, добавлять записи так же просто, как записывать их в конец буфера и обновлять хвостовой указатель.

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

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

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

person Timm    schedule 03.11.2009
comment
Блок, содержащий указатель на первую и последнюю запись, изнашивается быстрее, чем блоки, содержащие записи, поскольку его необходимо обновлять каждый раз при записи новой записи. Для некоторых флэш-памяти с малым количеством циклов записи это может произойти уже при 100 000-й записи. - person mjh2007; 13.01.2010

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

Я предполагаю, что величина изменчивости длины достаточно высока, чтобы дополнить все до фиксированной длины не вариант.

Сегмент записи должен отслеживать адрес, представляющий начало следующей записи для записи. Если вы заранее знаете размер блока для записи, вы можете сказать, закончите ли вы в конце логического буфера и начнете ли вы с «0». Я бы не стал делить пластинку на часть в конце и часть в начале.

Отдельный регистр может отслеживать начало; это самые старые данные, которые еще не были перезаписаны. Если бы вы пошли считывать данные, вы бы начали именно с этого.

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

По крайней мере, я бы, наверное, так и сделал. ХТН

person Mikeb    schedule 03.11.2009

Я вижу три варианта:

вариант 1: дополнить все до одинакового размера, это просто, сохранить указатель на начало и конец буфера, чтобы вы знали, где писать и откуда начинать чтение, использовать размер каждого объекта, чтобы получить смещение к следующему, это означает, что вам нужно пересечь буфер, как если бы вы были связным списком, то есть медленным, если вам нужен элемент 5000.

вариант 2: хранить только указатели на реальные данные в циклическом буфере, таким образом, когда вы зацикливаетесь, вам не приходится иметь дело с несоответствиями размеров. если вы храните реальные данные в циклическом буфере и не дополняете его, вы можете столкнуться с ситуациями, когда вы переусердствуете с несколькими элементами с 1 новым объектом данных, я предполагаю, что это не нормально.

храните фактические данные в другом месте во флэш-памяти, большинство флэш-памяти будет иметь какое-то встроенное выравнивание износа, если это так, вам не нужно беспокоиться о перезаписывании одного и того же места несколько раз, IC выяснит, где на самом деле хранить их на чипе, просто напишите в следующее доступное свободное место.

это означает, что вам нужно выбрать максимальный размер кольцевого буфера. То, как вы это сделаете, зависит от изменчивости данных. Если размер данных сильно изменился, скажем, всего на несколько байтов, то вам следует просто дополнить его и использовать вариант 1. Если размер сильно и непредсказуемо меняется, выберите наибольший размер, который может быть, и выясните, сколько объектов такого размера поместится в вашу флеш-память, используйте это как максимальное количество записей в буфере. Это означает, что вы тратите кучу места.

вариант 3: если объект действительно может быть любого размера, вы находитесь в точке, где вы должны просто использовать файловую систему, называть файлы по порядку и возвращаться назад, когда вы полностью помните, если ваша новая запись большая, вам, возможно, придется удалить несколько старых записей, чтобы вместить его. На самом деле это просто расширение варианта 2, поскольку вариант 2 во многих отношениях представляет собой простую файловую систему.

person Mark    schedule 03.11.2009
comment
Будьте осторожны с предположением о выравнивании износа... Верно, если у вас есть интерфейс типа USB или SD. Не так верно, если вы имеете дело непосредственно с флэш-частью. - person Benoit; 04.11.2009

«Круговой» во флэш-памяти можно сделать на основе размера блока, что означает, что вы должны объявить, сколько блоков флэш-памяти вы выделяете для этого буфера.

Фактический размер буфера будет в каждый конкретный момент времени между n-1 (n — количество блоков) и n.

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

Каждый элемент инкапсулирован с заголовком и нижним колонтитулом. заголовок по умолчанию содержит все, что вы хотите, но в соответствии с этим заголовком вы должны знать размер элемента. Нижний колонтитул по умолчанию — 0xFFFFFFFF. Это значение указывает на нулевое завершение.

В вашей оперативной памяти вы должны сохранить указатель на самый старый блок и самый последний блок, а также указатель на самый старый элемент и последний элемент. При включении вы просматриваете все блоки, находите соответствующие блоки и загружаете их.

Когда вы хотите сохранить новый элемент, вы проверяете, достаточно ли места в последнем блоке для этого элемента. Если это так, вы сохраняете элемент в конце предыдущего элемента и изменяете предыдущий нижний колонтитул, чтобы он указывал на этот элемент. Если в нем недостаточно места, вам нужно стереть самый старый блок. Прежде чем стереть этот блок, измените самые старые элементы блока (ОЗУ) так, чтобы они указывали на следующий блок, а самый старый элемент — на первый элемент в этом блоке. Затем вы можете сохранить новый элемент в этом блоке и изменить нижний колонтитул последнего элемента, чтобы он указывал на этот элемент.

Я знаю, что объяснение может показаться сложным, но процесс очень прост, и если вы напишите его правильно, вы можете сделать его даже безопасным при сбое питания (всегда помните о порядке записи).

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

person Barak C    schedule 04.11.2009