nRF5 SDK Flash Storage Печать
Добавил(а) microsin   

Flash Storage (или для краткости fstorage) это модуль для сохранения и стирания данных в постоянном хранилище, организованном в памяти FLASH микроконтроллера [1]. Этот модуль работает как обертка над SoftDevice flash API, принимая запросы на сохранение или стирание страниц с данными. Эти запросы ставятся в очередь для дальнейшей асинхронной обработки. Приложение оповещается о результатах операции через вызовы callback-функций для зарегистрированных обработчиков событий.

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

Модуль Experimental: Flash Data Storage [2] использует внутри себя fstorage. Также fstorage может быть использован напрямую.

[Регистрация использования]

Модуль fstorage может использоваться разными приложениями, или разными частями приложения одновременно (но только не в нескольких потоках, т. е. не обеспечивается thread-safe функционирование). Каждый пользователь flash storage должен зарегистрироваться с модулем, чтобы запросить определенное количество страниц хранилища. Страница (page) в fstorage это физическая страница памяти FLASH микроконтроллера, размер которой зависит от модели чипа. После этого модуль дает доступ только к зарегистрированным страницам, не давая возможности обратиться к FLASH по адресам, выходящих за область зарегистрированных страниц. Все зарегистрированные пользователи используют свой собственный callback-обработчик, и принимают обновления страниц, которые они зарегистрировали для своего использования.

Регистрация использования осуществляется во время компиляции через переменные секции [3]. Пользователь должен предоставить указатель на функцию, которая будет использована для обработки событий (event callbacks), количество страниц для резервирования и приоритет, и приоритет, определяющий способ назначения пространства в памяти FLASH. Эти параметры задаются фиксировано во время компиляции (compile time), и не могут быть изменены во время работы приложения (run time).

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

Для регистрации использования fstorage вызовите макрос FS_REGISTER_CFG, который определен в заголовке fstorage.h. Поместите в приложение код, аналогичный приведенному примеру ниже, чтобы создать переменную секции fs_config, содержащую конфигурацию для fstorage:

#include "fstorage.h"
 
FS_REGISTER_CFG(fs_config_t fs_config) =
{
   .callback  = fs_evt_handler, // Функция для обработки событий (event callbacks).
   .num_pages = NUM_PAGES,      // Количество требуемых физических страниц памяти FLASH.
   .priority  = 0xFE            // Приоритет использования FLASH.
};

[Обработчик события]

Следующий пример показывает декларацию обработчика событий (event handler) модуля fstorage:

static void fs_evt_handler(fs_evt_t const * const evt, fs_ret_t result)
{
   if (result != FS_SUCCESS)
   {
      // Произошла ошибка.
   }
}

[Приоритет для использования FLASH]

Для каждой регистрации модуля fstorage обязательно нужно указать приоритет, с которым fstorage назначает пространство FLASH для модуля. Для приоритета возможны значения от 0 до 255, причем 255 зарезервировано для использования модулем Peer Manager [4]. Все эти сконфигурированные приоритеты должны быть уникальны.

Flash storage назначает пространство FLASH с самым большим адресом памяти (сразу ниже загрузчика, если он присутствует) для модуля с самым присвоенным высоким приоритетом. Так что если, к примеру, у модуля 1 низкий приоритет, и ему нужна 1 страница, а у модуля 2 высокий приоритет, и ему нужно 2 страницы, то fstorage назначит эти 2 страницы для модуля 2 на самые старшие доступные адреса FLASH. Модуль 1 получит одну страницу сразу после этих двух страниц.

[Инициализация]

Следующий пример кода показывает, как инициализировать fstorage:

fs_ret_t ret = fs_init();
if (ret != FS_SUCCESS)
{
   // Произошла ошибка.
}

[Сохранение и стирание данных]

Flash storage ставит в очередь запросы на операции с FLASH и взаимодействие с кодом SoftDevice, чтобы получить интервалы времени для обработки этих операций по порядку. Запросы на сохранение больших объемов данных делятся на несколько операций, чтобы оптимизировать взаимодействие с SoftDevice при получение желаемых слотов времени. Максимальное количество слов в одном сохранении может быть указано макросом FS_MAX_WRITE_SIZE_WORDS в заголовке fstorage_config.h. Запросы на стирание нескольких страниц делятся на операции стирания страниц по отдельности.

Если SoftDevice не принял запрос, то fstorage повторяет поставленную в очередь операцию до тех пор, пока SoftDevice не примет запрос. Если SoftDevice принял запрос, но при этом столкнулся с ошибкой в планировании операции FLASH и произошел таймаут (это может произойти, к примеру, из-за высокой активности BLE), то fstorage повторит запрос некоторое предварительно сконфигурированное количество раз. Это максимальное количество повторов может быть задано макросом FS_OP_MAX_RETRIES в заголовке fstorage_config.h. Зарегистрированный пользователь оповещается об успехе или отказе операции путем вызова event callback.

Следующий пример кода показывает, как сохранить данные. Предполагается, что fs_config это переменная секции, которая хранит конфигурацию fstorage:

static uint32_t data = 0xAAAAAAAA;
 
fs_ret_t ret = fs_store(&fs_config, fs_config.p_start_addr, &data, 1);
if (ret != FS_SUCCESS)
{
   // Произошла ошибка.
}

Следующий пример кода показывает стирание страниц:

#define PAGE_SIZE_WORDS 1024
 
// Получение адреса страницы.
static uint32_t const * address_of_page(uint16_t page_num)
{
   return fs_config.p_start_addr + (page_num * PAGE_SIZE_WORDS);
}
 
fs_ret_t ret;
 
// Стирание одной страницы (страница 0).
ret = fs_erase(&fs_config, address_of_page(0), 1);
if (ret != FS_SUCCESS)
{
   // Произошла ошибка.
}
 
// Стирание двух страниц, начиная со страницы 3.
ret = fs_erase(&fs_config, address_of_page(3), 2);
if (ret != FS_SUCCESS)
{
   // Произошла ошибка.
}

Успех или отказ каждой операции будет показан вызовами обработчика (event callbacks). Поэтому проверка кода возврата всего лишь покажет, была ли успешно вызвана функция для постановки операции в очередь, но этот код возврата ничего не будет говорить о том, выполнилась ли операция на самом деле.

[Ссылки]

1. nRF5 SDK v13 Experimental Flash Storage site:nordicsemi.com.
2. nRF5 SDK Flash Data Storage.
3. nRF5 SDK Section Variables.
4. nRF5 SDK Peer Manager.