Кольцевой буфер в Flash

Адресная арифметика с указателями.

Это - на самом деле функция C, но я заметил, что немного людей, которые используют C/C++, действительно знают, что это даже существует. Я полагаю, что эта функция языка C действительно показывает гению и видению его изобретателя.

, Короче говоря, адресная арифметика с указателями позволяет компилятору работать [n] как * (a+n) для любого типа a. Как примечание стороны, как '+' коммутативный [n], конечно, эквивалентно n.

7
задан Dukeling 15 September 2013 в 22:27
поделиться

5 ответов

First, block management:

Put a smaller header at the start of each block. The main thing you need to keep track of the "oldest" and "newest" is a block number, which simply increments modulo k. k must be greater than your total number of blocks. Ideally, make k less than your MAX value (e.g. 0xFFFF) so you can easily tell what is an erased block.

At start-up, your code reads the headers of each block in turn, and locates the first and last blocks in the sequence that is ni+1 = (ni + 1) MODULO k. Take care not to get confused by erased blocks (block number is e.g. 0xFFFF) or data that is somehow corrupted (e.g. incomplete erase).

Within each block

Each block initially starts empty (each byte is 0xFF). Each record is simply written one after the other. If you have fixed-size records, then you can access it with a simple index. If you have variable-size records, then to read it you have to scan from the start of the block, linked-list style.

If you want to have variable-size records, but avoid linear scan, then you could have a well defined header on each record. E.g. use 0 as a record delimiter, and COBS-encode (or COBS/R-encode) each record. Or use a byte of your choice as a delimiter, and 'escape' that byte if it occurs in each record (similar to the PPP protocol).

At start-up, once you know your latest block, you can do a linear scan for the latest record. Or if you have fixed-size records or record delimiters, you could do a binary search.

Erase scheduling

For some Flash memory chips, erasing a block can take significant time--e.g. 5 seconds. Consider scheduling an erase as a background task a bit "ahead of time". E.g. when the current block is x% full, then start erasing the next block.

Record numbering

You may want to number records. The way I've done it in the past is to put, in the header of each block, the record number of the first record. Then the software has to keep count of the numbers of each record within the block.

Checksum or CRC

If you want to detect corrupted data (e.g. incomplete writes or erases due to unexpected power failure), then you can add a checksum or CRC to each record, and perhaps to the block header. Note the block header CRC would only cover the header itself, not the records, since it could not be re-written when each new record is written.

12
ответ дан 6 December 2019 в 14:05
поделиться

Keep a separate block that contains a pointer to the start of the first record and the end of the last record. You can also keep more information like the total number of records, etc.

Until you initially run out of space, adding records is as simple as writing them to the end of the buffer and updating the tail pointer.

As you need to reclaim space, delete enough records so that you can fit your current record. Update the head pointer as you delete records.

You'll need to keep track of how much extra space has been freed. If you keep a pointer to end of the last record, the next time you need to add a record, you can compare that with the pointer to the first record to determine if you need to delete any more records.

Also, if this is NAND, you or the flash controller will need to do deblocking and wear-leveling, but that should all be at a lower layer than allocating space for the circular buffer.

2
ответ дан 6 December 2019 в 14:05
поделиться

Самое простое решение, которое я нашел, - это запустить Imagination PVRTexTool для Windows с помощью Darwine (теперь WineBottler) .

Изменить: ] Как указывает gmaclachlan, zip-файл PVRTexTool теперь включает версии OS X как инструмента командной строки, так и графического интерфейса пользователя (который работает под X11); так что вам больше не придется возиться с WineBottler.

Вам нужно зарегистрироваться в качестве разработчика Imagination , прежде чем вы сможете скачать PVRTexTool (это бесплатно).

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

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

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

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

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

0
ответ дан 6 December 2019 в 14:05
поделиться

WIX - это стандарт для создания файлов MSI. Изучать IMO несколько сложно и неприятно, но оно того стоит. Запланируйте день, чтобы запустить базовый установщик. Это инструмент, который используют Microsoft и многие другие фирмы.

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

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

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

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

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

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

0
ответ дан 6 December 2019 в 14:05
поделиться

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

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

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

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

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

По крайней мере, наверное, я бы так и поступил. HTH

Если бы вы пошли зачитывать данные, именно здесь вы бы начали.

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

По крайней мере, наверное, я бы так и поступил. HTH

Если бы вы пошли зачитывать данные, именно здесь вы бы начали.

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

По крайней мере, наверное, я бы так и поступил. HTH

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

По крайней мере, вероятно, я бы так и поступил. HTH

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

По крайней мере, наверное, я бы так и поступил. HTH

1
ответ дан 6 December 2019 в 14:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: