Merge pull request #146 from kaans/feature/esp32_spi_flash_demo

Add demo project for esp32
This commit is contained in:
朱天龙 (Armink) 2022-04-25 14:17:04 +08:00 committed by GitHub
commit a7b33d810a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1838 additions and 3 deletions

4
demos/esp32_spi_flash/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/build
sdkconfig*
!sdkconfig.defaults

View File

@ -0,0 +1,10 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
list(APPEND EXTRA_COMPONENT_DIRS
"${CMAKE_CURRENT_LIST_DIR}/components")
project(esp32_spi_flash)

View File

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := flashDB_demo
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,14 @@
# flashDB demo esp32 Example
built with ESP IDF version 4.4.1 (v4.4.1-64-g4b2098bc58) using cmake.
run `idf.py build` in this directory and then flash with `idf.py flash` and monitor
the output with `idf.py monitor`.
A custom partition table is required so that a partition can be created for the FlashDB.
The size in the demo is set to 32K, see file `partitions.csv`. Custom partitions are
enabled by default in `sdkconfig.defaults`.
The file `sdkconfig.defaults` contains by default all values required for the demo to work,
i.e. the custom partitions are configured. By default the SPI flash is configured to
be 4MB.

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "porting/fal_flash_esp32_port.c"
INCLUDE_DIRS "inc" "../../../../port/fal/inc"
REQUIRES "spi_flash")

View File

@ -0,0 +1,19 @@
#
# Component Makefile
#
COMPONENT_ADD_INCLUDEDIRS += \
inc \
../../../../inc \
../../../../port/fal/inc
COMPONENT_SRCDIRS += \
../../../../src \
../../../../samples \
../../../../port/fal/src \
porting
# COMPONENT_PRIV_INCLUDEDIRS +=
# COMPONENT_ADD_LDFLAGS += -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2022, kaans, <https://github.com/kaans>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
//#define FAL_DEBUG 1
#define FAL_PART_HAS_TABLE_CFG
#define NOR_FLASH_DEV_NAME "norflash0"
//#define FAL_PART_TABLE_FLASH_DEV_NAME NOR_FLASH_DEV_NAME
//#define FAL_PART_TABLE_END_OFFSET 65536
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev nor_flash0;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&nor_flash0, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "fdb_kvdb1", NOR_FLASH_DEV_NAME, 0, 16 * 1024, 0}, \
{FAL_PART_MAGIC_WORD, "fdb_tsdb1", NOR_FLASH_DEV_NAME, 16 * 1024, 16 * 1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022, kaans, <https://github.com/kaans>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief configuration file
*/
#ifndef _FDB_CFG_H_
#define _FDB_CFG_H_
/* using KVDB feature */
#define FDB_USING_KVDB
#ifdef FDB_USING_KVDB
/* Auto update KV to latest default when current KVDB version number is changed. @see fdb_kvdb.ver_num */
/* #define FDB_KV_AUTO_UPDATE */
#endif
/* using TSDB (Time series database) feature */
#define FDB_USING_TSDB
/* Using FAL storage mode */
#define FDB_USING_FAL_MODE
/* the flash write granularity, unit: bit
* only support 1(nor flash)/ 8(stm32f2/f4)/ 32(stm32f1) */
#define FDB_WRITE_GRAN 1 /* @note you must define it for a value */
/* MCU Endian Configuration, default is Little Endian Order. */
/* #define FDB_BIG_ENDIAN */
/* log print macro using ESP_LOG.
* Need to include esp_log.h when setting FDB_PRINT to ESP_LOGI().
* default EF_PRINT macro is printf() */
//#include <esp_log.h>
//#define FDB_PRINT(...) ESP_LOGI("fdb", __VA_ARGS__)
/* print debug information */
#define FDB_DEBUG_ENABLE
#endif /* _FDB_CFG_H_ */

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2022, kaans, <https://github.com/kaans>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include <esp_partition.h>
#include <string.h>
#include <fal.h>
#define FLASH_ERASE_MIN_SIZE (4 * 1024)
#define LOCKER_ENABLE
#ifdef LOCKER_ENABLE
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
static SemaphoreHandle_t s_lock = NULL;
const static esp_partition_t *partition;
#define LOCK() \
do \
{ \
xSemaphoreTake(s_lock, portMAX_DELAY); \
} while (0)
#define UNLOCK() \
do \
{ \
xSemaphoreGive(s_lock); \
} while (0)
#else
#define LOCK()
#define UNLOCK()
#endif
static int init(void)
{
#ifdef LOCKER_ENABLE
if (s_lock == NULL)
{
s_lock = xSemaphoreCreateCounting(1, 1);
assert(s_lock != NULL);
}
#endif
// the values passed to esp_partition_find_first() must correspond to the
// values set in partitions.csv for the partition named "flashdb".
partition = esp_partition_find_first(0x40, 0x00, "flashdb");
assert(partition != NULL);
return 1;
}
static int read(long offset, uint8_t *buf, size_t size)
{
esp_err_t ret;
LOCK();
ret = esp_partition_read(partition, offset, buf, size);
UNLOCK();
return ret;
}
static int write(long offset, const uint8_t *buf, size_t size)
{
esp_err_t ret;
LOCK();
ret = esp_partition_write(partition, offset, buf, size);
UNLOCK();
return ret;
}
static int erase(long offset, size_t size)
{
esp_err_t ret;
int32_t erase_size = ((size - 1) / FLASH_ERASE_MIN_SIZE) + 1;
LOCK();
ret = esp_partition_erase_range(partition, offset, erase_size * FLASH_ERASE_MIN_SIZE);
UNLOCK();
return ret;
}
const struct fal_flash_dev nor_flash0 =
{
.name = NOR_FLASH_DEV_NAME,
.addr = 0x0, // address is relative to beginning of partition; 0x0 is start of the partition
.len = 32 * 1024, // size of the partition as specified in partitions.csv
.blk_size = FLASH_ERASE_MIN_SIZE, // must be 4096 bytes
.ops = {init, read, write, erase},
.write_gran = 1, // 1 byte write granularity
};

View File

@ -0,0 +1,13 @@
set (SOURCES)
list (APPEND SOURCES "main.c")
list (APPEND SOURCES "../../../src/fdb.c" "../../../src/fdb_file.c" "../../../src/fdb_kvdb.c" "../../../src/fdb_tsdb.c" "../../../src/fdb_utils.c")
list (APPEND SOURCES "../../../port/fal/src/fal_flash.c" "../../../port/fal/src/fal_partition.c" "../../../port/fal/src/fal_rtt.c" "../../../port/fal/src/fal.c")
list (APPEND SOURCES "../../../samples/kvdb_basic_sample.c" "../../../samples/kvdb_type_blob_sample.c" "../../../samples/kvdb_type_string_sample.c" "../../../samples/tsdb_sample.c")
idf_component_register(SRCS "${SOURCES}"
INCLUDE_DIRS "../components/FlashDB/inc" "../../../inc" "../../../port/fal/inc"
REQUIRES "spi_flash")

View File

@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,161 @@
/* FlashDB ESP32 SPI Flash Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include <flashdb.h>
#define FDB_LOG_TAG "[main]"
static uint32_t boot_count = 0;
static time_t boot_time[10] = {0, 1, 2, 3};
/* default KV nodes */
static struct fdb_default_kv_node default_kv_table[] = {
{"username", "armink", 0}, /* string KV */
{"password", "123456", 0}, /* string KV */
{"boot_count", &boot_count, sizeof(boot_count)}, /* int type KV */
{"boot_time", &boot_time, sizeof(boot_time)}, /* int array type KV */
};
/* KVDB object */
static struct fdb_kvdb kvdb = {0};
/* TSDB object */
struct fdb_tsdb tsdb = {0};
/* counts for simulated timestamp */
static int counts = 0;
static SemaphoreHandle_t s_lock = NULL;
extern void kvdb_basic_sample(fdb_kvdb_t kvdb);
extern void kvdb_type_string_sample(fdb_kvdb_t kvdb);
extern void kvdb_type_blob_sample(fdb_kvdb_t kvdb);
extern void tsdb_sample(fdb_tsdb_t tsdb);
static void lock(fdb_db_t db)
{
xSemaphoreTake(s_lock, portMAX_DELAY);
}
static void unlock(fdb_db_t db)
{
xSemaphoreGive(s_lock);
}
static fdb_time_t get_time(void)
{
/* Using the counts instead of timestamp.
* Please change this function to return RTC time.
*/
return ++counts;
}
int flashdb_demo(void)
{
fdb_err_t result;
if (s_lock == NULL)
{
s_lock = xSemaphoreCreateCounting(1, 1);
assert(s_lock != NULL);
}
#ifdef FDB_USING_KVDB
{ /* KVDB Sample */
struct fdb_default_kv default_kv;
default_kv.kvs = default_kv_table;
default_kv.num = sizeof(default_kv_table) / sizeof(default_kv_table[0]);
/* set the lock and unlock function if you want */
fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_LOCK, lock);
fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_UNLOCK, unlock);
/* Key-Value database initialization
*
* &kvdb: database object
* "env": database name
* "fdb_kvdb1": The flash partition name base on FAL. Please make sure it's in FAL partition table.
* Please change to YOUR partition name.
* &default_kv: The default KV nodes. It will auto add to KVDB when first initialize successfully.
* NULL: The user data if you need, now is empty.
*/
result = fdb_kvdb_init(&kvdb, "env", "fdb_kvdb1", &default_kv, NULL);
if (result != FDB_NO_ERR)
{
return -1;
}
/* run basic KV samples */
kvdb_basic_sample(&kvdb);
/* run string KV samples */
kvdb_type_string_sample(&kvdb);
/* run blob KV samples */
kvdb_type_blob_sample(&kvdb);
}
#endif /* FDB_USING_KVDB */
#ifdef FDB_USING_TSDB
{ /* TSDB Sample */
/* set the lock and unlock function if you want */
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_LOCK, lock);
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_UNLOCK, unlock);
/* Time series database initialization
*
* &tsdb: database object
* "log": database name
* "fdb_tsdb1": The flash partition name base on FAL. Please make sure it's in FAL partition table.
* Please change to YOUR partition name.
* get_time: The get current timestamp function.
* 128: maximum length of each log
* NULL: The user data if you need, now is empty.
*/
result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", get_time, 128, NULL);
/* read last saved time for simulated timestamp */
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_GET_LAST_TIME, &counts);
if (result != FDB_NO_ERR)
{
return -1;
}
/* run TSDB sample */
tsdb_sample(&tsdb);
}
#endif /* FDB_USING_TSDB */
return 0;
}
void app_main()
{
printf("FlashDB ESP32 SPI Flash Demo\n");
/* Print chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
printf("This is ESP32 chip with %d CPU cores, WiFi, ",
chip_info.cores);
printf("silicon revision %d, ", chip_info.revision);
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
flashdb_demo();
for (int i = 1000; i >= 0; i--)
{
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");
fflush(stdout);
esp_restart();
}

View File

@ -0,0 +1,14 @@
# The partition named "flashdb" will contain the partitions for the kvdb and tsdb.
# Note that this partition must be at least as large as the sum of all partitions as
# defined in FAL_PART_TABLE in fal_cfg.h.
# The offsets are left blank intentionally so that the partitions will be arranged
# automatically.
# The partition type for the partition "flashdb" was set to 0x40, a custom type.
# The subtype was set to 0x0. These values must correspond to the settings in the
# init() function in fal_flash_esp32_port.c.
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, , 16k,
phy_init, data, phy, , 4k,
flashdb, 0x40, 0x00, , 32k,
factory, app, factory, , 1M,
Can't render this file because it contains an unexpected character in line 1 and column 23.

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,12 @@
#define FDB_LOG_TAG "[sample][tsdb]" #define FDB_LOG_TAG "[sample][tsdb]"
#ifdef FDB_USING_TIMESTAMP_64BIT
#define __PRITS "ld"
#else
#define __PRITS "d"
#endif
struct env_status { struct env_status {
int temp; int temp;
int humi; int humi;
@ -90,7 +96,7 @@ static bool query_cb(fdb_tsl_t tsl, void *arg)
fdb_tsdb_t db = arg; fdb_tsdb_t db = arg;
fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &status, sizeof(status)))); fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &status, sizeof(status))));
FDB_INFO("[query_cb] queried a TSL: time: %ld, temp: %d, humi: %d\n", tsl->time, status.temp, status.humi); FDB_INFO("[query_cb] queried a TSL: time: %" __PRITS ", temp: %d, humi: %d\n", tsl->time, status.temp, status.humi);
return false; return false;
} }
@ -102,7 +108,7 @@ static bool query_by_time_cb(fdb_tsl_t tsl, void *arg)
fdb_tsdb_t db = arg; fdb_tsdb_t db = arg;
fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &status, sizeof(status)))); fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &status, sizeof(status))));
FDB_INFO("[query_by_time_cb] queried a TSL: time: %ld, temp: %d, humi: %d\n", tsl->time, status.temp, status.humi); FDB_INFO("[query_by_time_cb] queried a TSL: time: %" __PRITS ", temp: %d, humi: %d\n", tsl->time, status.temp, status.humi);
return false; return false;
} }
@ -111,7 +117,7 @@ static bool set_status_cb(fdb_tsl_t tsl, void *arg)
{ {
fdb_tsdb_t db = arg; fdb_tsdb_t db = arg;
FDB_INFO("set the TSL (time %ld) status from %d to %d\n", tsl->time, tsl->status, FDB_TSL_USER_STATUS1); FDB_INFO("set the TSL (time %" __PRITS ") status from %d to %d\n", tsl->time, tsl->status, FDB_TSL_USER_STATUS1);
fdb_tsl_set_status(db, tsl, FDB_TSL_USER_STATUS1); fdb_tsl_set_status(db, tsl, FDB_TSL_USER_STATUS1);
return false; return false;