1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/Jieli-Tech-fw-AC63_BT_SDK

 / Детали:

ЗАМЕЧАНИЕ: Сохранение данных в внутренней флеш-памяти

Предстоит сделать
Владелец
Создано  
05.03.2025

Сохранение данных пользователя в внутренний flash возможным двумя способами

  1. Окружение VM
    SDK уже реализовал механизм двойной защиты хранения, циклический метод записи и балансировку процесса очистки.
    Размер области #define CONFIG_VM_LEAST_SIZE 8К //обязательно увеличивать в размерах 8К
    Минимальный размер может быть установлен как 8К; если он равен 8К, фактический максимальный размер составляет 4К. Лучше всего установить значение больше 16К.
    Идеальный размер: объём хранимых данных пользователя * 4
    Если отдельная запись превышает 512Б, рекомендуется использовать второй метод.

  2. Самостоятельная область
    Отводится область флэш-памяти с предоставлением интерфейсов чтения/записи/очистки, а способ хранения данных определяется клиентом.
    Характеристики флэш-памяти: возможность программирования на уровне байта, поддержка очистки секторов размером 4К, каждый раз перед записью требуется очистка.
    Помните: частое использование очистки недопустимо, так как у флэш-памяти есть ограниченный срок службы при очистках.### I. Способ использования окружения VM
    введите описание изображения здесь
    Для изменения размера области VM необходимо изменить два места: CONFIG_VM_LEAST_SIZE и изображение должны совпадать.

//Нормы использования окружения VM
//Чтение и запись флэш-памяти запрещены во время hi_timer и функций прерываний
//Размер области VM #define CONFIG_VM_LEAST_SIZE      8 КБ // увеличивается в размерах на 8 КБ
//syscfg_id.h    диапазон значений ID VM: CFG_USER_DEFINE_BEGIN(1) - CFG_USER_DEFINE_END(49)
//user_cfg_id.h  некоторые значения используются некоторыми приложениями, следите за тем, чтобы они не пересекались
//syscfg_read, syscfg_write возвращают отрицательные значения при ошибке VM_ERR, положительные значения — последнее переданное значение
//при недостатке ID VM объедините несколько переменных в один структурный тип
``````c
#define CFG_USER_VAR   2
#define CFG_USER_BUF   3
#define CFG_USER_STRUCT  4

typedef struct {
    u32 var1;
    u32 var2;
} var_struct;

static u32 var;
static u8 buf[512]  __attribute__((aligned(4)));
static var_struct var_t;

void vm_op_demo(void)
{
    log_info("%s", __func__);
    int ret = 0;
    // Variable
    var = 0;
    ret = syscfg_read(CFG_USER_VAR, &var, sizeof(u32)); // type of data variable
    log_info("%s[CFG_USER_VAR -> syscfg_read:%d]", __func__, ret);
    if(ret != sizeof(u32)) {
        log_error("CFG_USER_VAR -> syscfg_read -> err:%d", ret);
    } else {
        log_info("CFG_USER_VAR:%d", var);
    }
    var++;
    ret = syscfg_write(CFG_USER_VAR, &var, sizeof(u32)); // type of data variable
    log_info("%s[CFG_USER_VAR -> syscfg_write:%d]", __func__, ret);
    if(ret != sizeof(u32)) {
        log_error("CFG_USER_VAR -> syscfg_write -> err:%d", ret);
    }
}

// Array in the form of a buffer
memset(buf, 0x00, sizeof(buf));
ret = syscfg_read(CFG_USER_BUF, buf, sizeof(buf));
log_info("%s[CFG_USER_BUF -> syscfg_read:%d]", __func__, ret);
if (ret != sizeof(buf)) {
    log_error("CFG_USER_BUF -> syscfg_read -> error:%d", ret);
} else {
    log_info_hexdump(buf, sizeof(buf));
}
buf[0]++;
memset(buf, buf[0], sizeof(buf));
ret = syscfg_write(CFG_USER_BUF, buf, sizeof(buf));
log_info("%s[CFG_USER_BUF -> syscfg_write:%d]", __func__, ret);
if (ret != sizeof(buf)) {
    log_error("CFG_USER_BUF -> syscfg_write -> error:%d", ret);
}

// Form using structure
var_t.var1 = 0;
var_t.var2 = 0;
ret = syscfg_read(CFG_USER_STRUCT, &var_t, sizeof(var_struct));
log_info("%s[CFG_USER_STRUCT -> syscfg_read:%d]", __func__, ret);
if (ret != sizeof(var_struct)) {
    log_error("CFG_USER_STRUCT -> syscfg_read -> error:%d", ret);
} else {
    log_info("CFG_USER_STRUCT:%d %d", var_t.var1, var_t.var2);
}
var_t.var1++;
var_t.var2++;
ret = syscfg_write(CFG_USER_STRUCT, &var_t, sizeof(var_struct));
log_info("%s[CFG_USER_STRUCT -> syscfg_write:%d]", __func__, ret);
if (ret != sizeof(var_struct)) {
    log_error("CFG_USER_STRUCT -> syscfg_write -> error:%d", ret);
}
}
```### II. Способ чтения и записи пользовательской области
Добавьте следующий контент в isd_config_rule.c:

```plaintext
FORCE_4K_ALIGN = YES;     // принудительно выравнивать с 4к байтами
SPECIAL_OPT = 0;          // создать только один flash.bin
// COMPACT_SETTING = YES;  // USERIF_FILE=100kb.bin; если требуется указание файла, то добавьте эту строку

// AUTO: указывает на расположение сразу после предыдущей области
// USERIF_FILE=100kb.bin;
//# USERIF_ADR=0x50000;
USERIF_ADR=AUTO;
USERIF_LEN=32K;
USERIF_OPT=1;
// Размер области должен быть кратен 4К

введите описание изображения здесь
введите описание изображения здесь
введите описание изображения здесь

Ниже приведён пример нового C-файла, который можно скопировать целиком.

#include "system/includes.h"
#include "asm/includes.h"
#include "app_config.h"
```#undef _DEBUG_H_
#define LOG_TAG_CONST       FLASH_IF
#define LOG_TAG             "[FLASH_IF]"
#include "debug.h"
#define LOG_v(t)           лог_тэг_константа_v_##t
#define LOG_i(t)           лог_тэг_константа_i_##t
#define LOG_d(t)           лог_тэг_константа_d_##t
#define LOG_w(t)           лог_тэг_константа_w_##t
#define LOG_e(t)           лог_тэг_константа_e_##t
#define LOG_c(t)           лог_тэг_константа_c_##t
#define LOG_tag(tag, n)    n(tag)
const char LOG_tag(LOG_TAG_CONST, LOG_v) AT(".LOG_TAG_CONST") = 0;
const char LOG_tag(LOG_TAG_CONST, LOG_i) AT(".LOG_TAG_CONST") = 1;
const char LOG_tag(LOG_TAG_CONST, LOG_d) AT(".LOG_TAG_CONST") = 1;
const char LOG_tag(LOG_TAG_CONST, LOG_w) AT(".LOG_TAG_CONST") = 1;
const char LOG_tag(LOG_TAG_CONST, LOG_e) AT(".LOG_TAG_CONST") = 1;
const char LOG_tag(LOG_TAG_CONST, LOG_c) AT(".LOG_TAG_CONST") = 1;
```Примечание: В соответствии с правилами перевода, имена переменных, функций и других элементов кода остаются без изменения. Поэтому в данном случае было принято решение использовать английскую версию терминологии для констант и функций, чтобы избежать потенциальных проблем при компиляции кода.
//Старый SDK, определён в isd_config.ini
//Новый SDK, определён в isd_config_rule.c
///Пользовательская область флэш-памяти
//  #С учётом размера флэш-памяти микросхемы, последние 4К отводятся под резерв, адреса выбираются сверху
//  #USERIF_ADR=0x50000;
//  #USERIF_ADR=AUTO;
//  USERIF_LEN=32К;
//  USERIF_OPT=1;
///Адреса конфигурации isd_config.ini должны быть выровнены
///Выравнивание по 4К требуется для SECTOR_ERASER
///Выравнивание по 64К требуется для BLOCK_ERASER

typedef enum _FLASH_ERASER {
    CHIP_ERASER,
    BLOCK_ERASER, //64к
    SECTOR_ERASER,//4к
    PAGE_ERASER,  //256Б
} FLASH_ERASER;

extern bool sfc_erase(FLASH_ERASER cmd, u32 addr);
extern u32 sdfile_cpu_addr2flash_addr(u32 offset);
extern void clr_wdt(void);

static FILE *flash_area_init(const char *path)
{
    log_info("%s", path);
    FILE *fp = NULL;
    struct vfs_attr attr = {0};
    fp = fopen(path, "r+");
    if(fp == NULL){
        log_info("%s[%s]", __func__, "open failed!!!");
        return NULL;
    }
    fget_attrs(fp, &attr);
    log_info("%s[processor address:0x%x,size:%dK]", __func__, attr.sclust, attr.fsize / 1024);
    u32 flash_addr = sdfile_cpu_addr2flash_addr(attr.sclust);
    log_info("%s[flash memory address:0x%x,size:%dK]", __func__, flash_addr, attr.fsize / 1024);
    return fp;
}```c
static int flash_area_erase(FILE *fp)
{
    log_info("%s[0x%x]", __func__, fp);
    if (fp == NULL) {
        return -1;
    }
    struct vfs_attr attr = {0};
    fget_attrs(fp, &attr);
    u32 erase_total_size = attr.fsize;
    u32 erase_addr = sdfile_cpu_addr2flash_addr(attr.sclust);
    u32 erase_size = 4096;
    u32 erase_cmd = SECTOR_ERASER;
    log_info("%s[0x%x %dК]", __func__, erase_addr, erase_total_size / 1024);
    log_info("%s Выравнивание по 64К:%s", __func__, erase_addr % 0x10000 ? "false" : "true");
    log_info("%s Выравнивание по 4К:%s", __func__, erase_addr % 0x1000 ? "false" : "true");
    while (erase_total_size) {
        clr_wdt();
        // Операция очистки области
        sfc_erase(erase_cmd, erase_addr);
        erase_addr += erase_size;
        erase_total_size -= erase_size;
    }
    /* sfc_erase(BLOCK_ERASER, erase_addr); */
    /* sfc_erase(SECTOR_ERASER, erase_addr); */
    // После завершения очистки переместите указатель файла на позицию для записи
    fseek(fp, 0, SEEK_SET);
    return 0;
}
``````c
static u32 flash_area_size(FILE *fp)
{
    if (fp == NULL) {
        return -1;
    }
    struct vfs_attr attr = {0};
    fget_attrs(fp, &attr);
    log_info("%s[размер:%dК]", __func__, attr.fsize / 1024);
    return attr.fsize;
}

/// Пример использования
#define FLASH_AREA_NAME SDFILE_APP_ROOT_PATH "USERIF" // имя должно совпадать с именем в ini-файле
static u8 rbuf[4 * 1024] __attribute__((aligned(4)));
static u8 wbuf[4 * 1024] __attribute__((aligned(4)));
FILE *zone_fp = NULL;

void flash_area_test(void) {
    log_info("%s", __func__);

    extern __attribute__((weak)) u8 *get_norflash_uuid(void);
    u8 flash_uuid[16] = {0};
    memcpy(flash_uuid, get_norflash_uuid(), 16);
    log_info("%s[flash_uuid:]", __func__);
    put_buf(flash_uuid, 16);

    u32 flash_capacity = sdfile_get_disk_capacity();
    log_info("%s[flash_capacity:%dКБ]", __func__, flash_capacity / 1024);

    zone_fp = flash_area_init(FLASH_AREA_NAME);
    if (zone_fp == NULL) {
        return;
    }

    int ret = 0;
    FILE *fp = zone_fp;
    int start_addr = 0;
    u32 size = flash_area_size(fp);

    memset(rbuf, 0x00, sizeof(rbuf));
    log_info("%s[memset rbuf 0x00]", __func__);
    put_buf(rbuf, 16);

    fseek(fp, 0, SEEK_SET);
    start_addr = fpos(fp);
    ret = fread(fp, rbuf, sizeof(rbuf)); // чтение данных первого сектора размером 4КБ
    log_info("%s[fread:0x%x %d]", __func__, start_addr, ret);
    put_buf(rbuf, 16);

    fseek(fp, size - 4096, SEEK_SET);
    start_addr = fpos(fp);
    ret = fread(fp, rbuf, sizeof(rbuf)); // чтение данных последнего сектора размером 4КБ
    log_info("%s[fread:0x%x %d]", __func__, start_addr, ret);
    put_buf(rbuf, 16);

    ret = flash_area_erase(fp); // очистка всего региона
    log_info("%s[очистка:%d]", __func__, ret);

    for (u16 i = 0; i < sizeof(wbuf); i++) {
        wbuf[i] = rbuf[i] + i + 1;
    }

    fseek(fp, 0, SEEK_SET);
    start_addr = fpos(fp);
    ret = fwrite(fp, wbuf, sizeof(wbuf)); // запись данных первого сектора размером 4КБ
    log_info("%s[fwrite:0x%x %d]", __func__, start_addr, ret);
    put_buf(wbuf, 16);
}
``````c
fseek(fp, size - 4096, SEEK_SET);
start_addr = fpos(fp);
ret = fwrite(fp, wbuf, sizeof(wbuf)); // Запись данных последнего сектора размером 4КБ
log_info("%s[fwrite:0x%x %d]", __func__, start_addr, ret);
put_buf(wbuf, 16);

memset(rbuf, 0x00, sizeof(rbuf));
log_info("%s[reset rbuf 0x00]", __func__);
put_buf(rbuf, 16);

fseek(fp, 0, SEEK_SET);
start_addr = fpos(fp);
ret = fread(fp, rbuf, sizeof(rbuf)); // Чтение данных первого сектора размером 4КБ
log_info("%s[fread:0x%x %d]", __func__, start_addr, ret);
put_buf(rbuf, 16);
}

fseek(fp, size - 4096, SEEK_SET);
start_addr = fpos(fp);
ret = fread(fp, rbuf, sizeof(rbuf)); // Чтение последних 4К данных сектора
log_info("%s[fread:0x%x %d]", __func__, start_addr, ret);
put_buf(rbuf, 16);

if (0 == memcmp(rbuf, wbuf, sizeof(rbuf))) {
    log_info("rbuf и wbuf memcmp прошли успешно !!!!!!");
} else {
    log_error("rbuf и wbuf memcmp произошла ошибка !!!!!!!");
}

Комментарий (0)

GitLife Service Account Задача создана
GitLife Service Account добавлено
 
系统相关
label.
Развернуть журнал операций

Вход Перед тем как оставить комментарий

Статус
Ответственный
Контрольная точка
Pull Requests
Связанные запросы на слияние могут быть закрыты после их объединения
Ветки
Дата начала   -   Крайний срок
-
Закрепить/Открепить
Приоритет
Участники(1)
1
https://api.gitlife.ru/oschina-mirror/Jieli-Tech-fw-AC63_BT_SDK.git
git@api.gitlife.ru:oschina-mirror/Jieli-Tech-fw-AC63_BT_SDK.git
oschina-mirror
Jieli-Tech-fw-AC63_BT_SDK
Jieli-Tech-fw-AC63_BT_SDK