Окружение VM
SDK уже реализовал механизм двойной защиты хранения, циклический метод записи и балансировку процесса очистки.
Размер области #define CONFIG_VM_LEAST_SIZE 8К
//обязательно увеличивать в размерах 8К
Минимальный размер может быть установлен как 8К; если он равен 8К, фактический максимальный размер составляет 4К. Лучше всего установить значение больше 16К.
Идеальный размер: объём хранимых данных пользователя * 4
Если отдельная запись превышает 512Б, рекомендуется использовать второй метод.
Самостоятельная область
Отводится область флэш-памяти с предоставлением интерфейсов чтения/записи/очистки, а способ хранения данных определяется клиентом.
Характеристики флэш-памяти: возможность программирования на уровне байта, поддержка очистки секторов размером 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 произошла ошибка !!!!!!!");
}
Вход Перед тем как оставить комментарий