Hello,
I am trying to write data into an external flash memory using a custom board (NRF52840-QFAA).
The external flash is the W25Q256JVEIQ. I get a fs_write (-22) error at random times when writing to the file.
I have set the partition to 28MB and I am writing around 1-2MB of data inside the memory.
Please see my main file, prj.conf, device tree, pm_static.yml and the error I get
Can someone help me deduce the issue?
It would usually start letting me write if I reformat, but I dont want to reformat the memory because data will be lost.
[00:02:30.597,656] <inf> main: Synced to flash [00:02:31.478,820] <inf> main: Synced to flash [00:02:32.270,019] <inf> main: Synced to flash [00:02:33.162,933] <inf> main: Synced to flash [00:02:33.965,911] <inf> main: Synced to flash [00:02:34.774,444] <inf> main: Synced to flash [00:02:35.588,989] <inf> main: Synced to flash [00:02:36.408,905] <inf> main: Synced to flash [00:02:37.234,497] <inf> main: Synced to flash [00:02:38.116,210] <inf> main: Synced to flash [00:02:38.908,172] <inf> main: Synced to flash [00:02:39.705,780] <inf> main: Synced to flash [00:02:39.926,788] <err> fs: file write error (-22) [00:02:39.927,093] <err> main: fs_write failed (-22) [00:02:39.927,398] <wrn> main: Write returned -EINVAL; attempting FS recovery [00:02:39.927,825] <inf> littlefs: /lfs unmounted [00:02:39.928,131] <inf> littlefs: LittleFS version 2.9, disk version 2.1 [00:02:39.928,527] <inf> littlefs: FS at SPI_FLASH:0x0 is 7168 0x1000-byte blocks with 512 cycle [00:02:39.928,985] <inf> littlefs: sizes: rd 16 ; pr 256 ; ca 256 ; la 128 [00:02:39.943,023] <wrn> main: Filesystem recovery complete [00:02:40.177,398] <err> fs: file write error (-22) [00:02:40.177,703] <err> main: fs_write failed (-22) [00:02:40.178,009] <wrn> main: Write returned -EINVAL; attempting FS recovery [00:02:40.178,436] <inf> littlefs: /lfs unmounted [00:02:40.178,741] <inf> littlefs: LittleFS version 2.9, disk version 2.1 [00:02:40.179,138] <inf> littlefs: FS at SPI_FLASH:0x0 is 7168 0x1000-byte blocks with 512 cycle [00:02:40.179,595] <inf> littlefs: sizes: rd 16 ; pr 256 ; ca 256 ; la 128 [00:02:40.193,634] <wrn> main: Filesystem recovery complete [00:02:40.428,009] <err> fs: file write error (-22) [00:02:40.428,314] <err> main: fs_write failed (-22) [00:02:40.428,619] <wrn> main: Write returned -EINVAL; attempting FS recovery
// #include <zephyr/kernel.h>
// #include <zephyr/device.h>
// #include <zephyr/drivers/gpio.h>
// #include <zephyr/drivers/pwm.h>
// #include <zephyr/fs/fs.h>
// #include <zephyr/fs/littlefs.h>
// #include <zephyr/storage/flash_map.h>
// #include <zephyr/logging/log.h>
// #include <string.h>
// #include <errno.h>
// #include <stdint.h>
// #include <stdbool.h>
// #include <zephyr/drivers/flash.h>
// #include "clock_bt_setup.h"
// #include "sensor_fusion.h"
// #include "bluetooth_conn.h"
// LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
// /* =========================
// * Flash / FS
// * ========================= */
// #define LFS_PARTITION_ID FLASH_AREA_ID(lfs_partition)
// static struct fs_littlefs lfs_cfg = {
// .cfg = {
// .read_size = 16,
// .prog_size = 16,
// .cache_size = 256,
// .lookahead_size = 128,
// .block_cycles = 512,
// }
// };
// static struct fs_mount_t littlefs_mnt = {
// .type = FS_LITTLEFS,
// .fs_data = &lfs_cfg,
// .storage_dev = (void *)LFS_PARTITION_ID,
// .mnt_point = "/lfs",
// };
// /* =========================
// * Hardware
// * ========================= */
// #define LED_G_NODE DT_PATH(pwmleds, led_g)
// #define LED_B_NODE DT_PATH(pwmleds, led_b)
// static const struct pwm_dt_spec pwm_g = PWM_DT_SPEC_GET(LED_G_NODE);
// static const struct pwm_dt_spec pwm_b = PWM_DT_SPEC_GET(LED_B_NODE);
// #define EXT_SWITCH_NODE DT_PATH(buttons, ext_switch)
// #define SWITCH_NODE DT_PATH(buttons, sw1)
// static const struct gpio_dt_spec ext_switch =
// GPIO_DT_SPEC_GET(EXT_SWITCH_NODE, gpios);
// static const struct gpio_dt_spec sw1 =
// GPIO_DT_SPEC_GET(SWITCH_NODE, gpios);
// /* =========================
// * Buttons
// * ========================= */
// #define BUTTON_POLL_MS 10
// #define BUTTON_DEBOUNCE_MS 40
// #define MULTICLICK_TIMEOUT_MS 500
// #define LONG_PRESS_MS 1500
// /* =========================
// * Logging config
// * ========================= */
// #define RECORDS_PER_BUFFER 1
// #define SYNC_INTERVAL_BYTES 4096
// #define SAMPLE_INTERVAL_MS 20
// #define LOG_SEGMENT_MS (5 * 60 * 1000)
// #define LOG_RESTART_DELAY_MS 1000
// #define TOTAL_LOG_TIME_MS (1 * 60 * 1000)
// #define LOG_FILE_PATH "/lfs/imu.bin"
// /* =========================
// * Logging buffer/state
// * ========================= */
// static size_t total_records_logged = 0;
// static sensor_sample_t record_buffer[RECORDS_PER_BUFFER]__aligned(16);
// static size_t buffer_index = 0;
// static size_t bytes_since_sync = 0;
// /* =========================
// * LED Helpers
// * ========================= */
// static void green_on(void)
// {
// (void)pwm_set_dt(&pwm_g, pwm_g.period, 0);
// }
// static void green_off(void)
// {
// (void)pwm_set_dt(&pwm_g, pwm_g.period, pwm_g.period);
// }
// static void blue_on(void)
// {
// (void)pwm_set_dt(&pwm_b, pwm_b.period, 0);
// }
// static void blue_off(void)
// {
// (void)pwm_set_dt(&pwm_b, pwm_b.period, pwm_b.period);
// }
// /* =========================
// * Button Helpers
// * ========================= */
// static bool button_pressed(const struct gpio_dt_spec *btn)
// {
// int val = gpio_pin_get_dt(btn);
// return (val > 0);
// }
// static void wait_for_release(const struct gpio_dt_spec *btn)
// {
// while (button_pressed(btn)) {
// k_msleep(BUTTON_POLL_MS);
// }
// }
// static uint8_t wait_for_clicks(const struct gpio_dt_spec *btn,
// uint8_t min, uint8_t max)
// {
// uint8_t count = 0;
// int64_t last = 0;
// bool prev = button_pressed(btn);
// wait_for_release(btn);
// while (1) {
// bool now = button_pressed(btn);
// if (now && !prev) {
// k_msleep(BUTTON_DEBOUNCE_MS);
// now = button_pressed(btn);
// if (now) {
// count++;
// last = k_uptime_get();
// LOG_INF("Button click count = %u", count);
// }
// }
// if (count >= min) {
// if ((k_uptime_get() - last) > MULTICLICK_TIMEOUT_MS) {
// return count;
// }
// }
// if (count >= max) {
// return count;
// }
// prev = now;
// k_msleep(BUTTON_POLL_MS);
// }
// }
// /* =========================
// * Boot Mode
// * ========================= */
// enum mode {
// MODE_IDLE,
// MODE_SYNC,
// MODE_LOG,
// MODE_TRANSFER
// };
// static enum mode wait_for_mode(void)
// {
// LOG_INF("Waiting for input: SW1 x2=SYNC, SW1 long press=LOG, EXT x2=TRANSFER");
// while (1) {
// if (button_pressed(&sw1)) {
// k_msleep(BUTTON_DEBOUNCE_MS);
// if (button_pressed(&sw1)) {
// int64_t press_start = k_uptime_get();
// while (button_pressed(&sw1)) {
// if ((k_uptime_get() - press_start) >= LONG_PRESS_MS) {
// LOG_INF("SW1 long press detected");
// wait_for_release(&sw1);
// return MODE_LOG;
// }
// k_msleep(BUTTON_POLL_MS);
// }
// uint8_t c = wait_for_clicks(&sw1, 2, 2);
// if (c == 2) {
// return MODE_SYNC;
// }
// }
// }
// if (button_pressed(&ext_switch)) {
// uint8_t c = wait_for_clicks(&ext_switch, 2, 2);
// if (c == 2) {
// return MODE_TRANSFER;
// }
// }
// k_msleep(10);
// }
// }
// /* =========================
// * FS Helpers
// * ========================= */
// static int mount_fs_no_format(void)
// {
// int rc = fs_mount(&littlefs_mnt);
// if (rc == 0) {
// LOG_INF("LittleFS mounted");
// return 0;
// }
// LOG_ERR("LittleFS mount failed (%d)", rc);
// return rc;
// }
// static void log_flash_params(void)
// {
// const struct flash_area *fa;
// int rc = flash_area_open(LFS_PARTITION_ID, &fa);
// if (rc < 0) {
// LOG_ERR("flash_area_open failed (%d)", rc);
// return;
// }
// const struct device *flash_dev = fa->fa_dev;
// if (!device_is_ready(flash_dev)) {
// LOG_ERR("Flash device not ready");
// flash_area_close(fa);
// return;
// }
// const struct flash_parameters *params = flash_get_parameters(flash_dev);
// size_t wbs = flash_get_write_block_size(flash_dev);
// LOG_INF("flash write_block_size=%u erase_value=0x%02x",
// (unsigned int)wbs,
// (unsigned int)params->erase_value);
// flash_area_close(fa);
// }
// static int format_and_mount_fs(void)
// {
// int rc;
// rc = fs_mkfs(FS_LITTLEFS, (uintptr_t)LFS_PARTITION_ID, &lfs_cfg, 0);
// if (rc < 0) {
// LOG_ERR("fs_mkfs failed (%d)", rc);
// return rc;
// }
// LOG_INF("LittleFS formatted");
// rc = fs_mount(&littlefs_mnt);
// if (rc < 0) {
// LOG_ERR("Mount after format failed (%d)", rc);
// return rc;
// }
// LOG_INF("LittleFS mounted after format");
// return 0;
// }
// static int open_log_file(struct fs_file_t *file, bool truncate_file)
// {
// int rc;
// fs_file_t_init(file);
// if (truncate_file) {
// rc = fs_open(file, LOG_FILE_PATH,
// FS_O_CREATE | FS_O_TRUNC | FS_O_RDWR);
// if (rc < 0) {
// LOG_ERR("File open (truncate) failed (%d)", rc);
// return rc;
// }
// LOG_INF("Opened %s as new file", LOG_FILE_PATH);
// return 0;
// }
// rc = fs_open(file, LOG_FILE_PATH,
// FS_O_CREATE | FS_O_APPEND | FS_O_RDWR);
// if (rc < 0) {
// LOG_ERR("File open (append) failed (%d)", rc);
// return rc;
// }
// off_t pos = fs_tell(file);
// LOG_INF("Opened %s for append, current pos=%lld bytes",
// LOG_FILE_PATH, (long long)pos);
// return 0;
// }
// static int flush_buffer(struct fs_file_t *file)
// {
// if (buffer_index == 0) {
// return 0;
// }
// size_t total_size = buffer_index * sizeof(sensor_sample_t);
// uint8_t *p = (uint8_t *)record_buffer;
// size_t remaining = total_size;
// off_t before = fs_tell(file);
// LOG_INF("flush_buffer: buffer_index=%u total_size=%u file_pos_before=%lld",
// (unsigned int)buffer_index,
// (unsigned int)total_size,
// (long long)before);
// while (remaining > 0) {
// size_t chunk = (remaining > 48) ? 48 : remaining;
// ssize_t written = fs_write(file, p, chunk);
// if (written < 0) {
// LOG_ERR("fs_write failed (%d) on chunk=%u file_pos_before_fail=%lld",
// (int)written,
// (unsigned int)chunk,
// (long long)fs_tell(file));
// return (int)written;
// }
// if ((size_t)written != chunk) {
// LOG_ERR("fs_write short (%d/%u)", (int)written,
// (unsigned int)chunk);
// return -EIO;
// }
// p += chunk;
// remaining -= chunk;
// bytes_since_sync += chunk;
// }
// buffer_index = 0;
// off_t after = fs_tell(file);
// LOG_INF("flush_buffer: file_pos_after=%lld", (long long)after);
// /* diagnostic: sync every flush */
// int rc = fs_sync(file);
// if (rc < 0) {
// LOG_ERR("fs_sync failed (%d)", rc);
// return rc;
// }
// bytes_since_sync = 0;
// LOG_INF("Synced to flash");
// return 0;
// }
// static int recover_filesystem_no_format(struct fs_file_t *file)
// {
// int rc;
// fs_close(file);
// fs_unmount(&littlefs_mnt);
// k_msleep(500);
// rc = fs_mount(&littlefs_mnt);
// if (rc < 0) {
// LOG_ERR("Mount failed during recovery (%d)", rc);
// return rc;
// }
// fs_file_t_init(file);
// rc = fs_open(file, LOG_FILE_PATH, FS_O_CREATE | FS_O_APPEND | FS_O_RDWR);
// if (rc < 0) {
// LOG_ERR("File open failed during recovery (%d)", rc);
// return rc;
// }
// buffer_index = 0;
// bytes_since_sync = 0;
// LOG_WRN("Filesystem recovery complete without formatting; append mode restored");
// green_on();
// k_msleep(500);
// green_off();
// return 0;
// }
// /* =========================
// * Logging
// * ========================= */
// static int start_logging_segment(struct fs_file_t *file, int64_t segment_ms)
// {
// int rc;
// bool led_state = false;
// uint32_t blink_count = 0;
// int64_t start_ms = k_uptime_get();
// int64_t next_sample_time = start_ms;
// buffer_index = 0;
// bytes_since_sync = 0;
// while ((k_uptime_get() - start_ms) < segment_ms) {
// sensor_sample_t r;
// rc = sensors_read(&r);
// if (rc < 0) {
// LOG_ERR("sensors_read failed (%d)", rc);
// return rc;
// }
// record_buffer[buffer_index++] = r;
// total_records_logged++;
// if (buffer_index >= RECORDS_PER_BUFFER) {
// rc = flush_buffer(file);
// if (rc < 0) {
// LOG_ERR("flush_buffer returned %d", rc);
// return rc;
// }
// }
// if (++blink_count >= 20) {
// led_state = !led_state;
// (void)pwm_set_dt(&pwm_b, pwm_b.period,
// led_state ? 0 : pwm_b.period);
// blink_count = 0;
// }
// next_sample_time += SAMPLE_INTERVAL_MS;
// int64_t now = k_uptime_get();
// if (next_sample_time > now) {
// k_msleep((int32_t)(next_sample_time - now));
// } else {
// next_sample_time = now;
// }
// }
// rc = flush_buffer(file);
// if (rc < 0) {
// LOG_ERR("final flush_buffer returned %d", rc);
// return rc;
// }
// rc = fs_sync(file);
// if (rc < 0) {
// LOG_ERR("fs_sync failed (%d)", rc);
// return rc;
// }
// LOG_INF("Segment complete, total records logged=%u",
// (unsigned int)total_records_logged);
// return 0;
// }
// /* =========================
// * Modes
// * ========================= */
// static int run_sync(void)
// {
// int rc = setup_clock();
// if (rc < 0) {
// LOG_ERR("setup_clock failed (%d)", rc);
// return rc;
// }
// bool state = false;
// while (!clock_bt_is_time_synced()) {
// state = !state;
// (void)pwm_set_dt(&pwm_g, pwm_g.period, state ? 0 : pwm_g.period);
// k_msleep(200);
// }
// green_on();
// k_msleep(1000);
// rc = shutdown_clock_bt();
// if (rc < 0) {
// LOG_ERR("shutdown_clock_bt failed (%d)", rc);
// return rc;
// }
// green_off();
// return 0;
// }
// static int run_log(void)
// {
// int rc;
// struct fs_file_t file;
// bool first_segment = true;
// int64_t total_start_ms;
// uint32_t segment_num = 0;
// green_off();
// blue_off();
// rc = sensors_init();
// if (rc < 0) {
// LOG_ERR("sensors_init failed (%d)", rc);
// return rc;
// }
// log_flash_params();
// total_records_logged = 0;
// buffer_index = 0;
// bytes_since_sync = 0;
// total_start_ms = k_uptime_get();
// while ((k_uptime_get() - total_start_ms) < TOTAL_LOG_TIME_MS) {
// int64_t elapsed_ms = k_uptime_get() - total_start_ms;
// int64_t remaining_ms = TOTAL_LOG_TIME_MS - elapsed_ms;
// int64_t this_segment_ms =
// (remaining_ms > LOG_SEGMENT_MS) ? LOG_SEGMENT_MS : remaining_ms;
// segment_num++;
// LOG_INF("Starting segment %u, duration=%lld ms",
// segment_num, (long long)this_segment_ms);
// /* Open fresh on first segment, append on later segments */
// if (first_segment) {
// rc = format_and_mount_fs();
// if (rc < 0) {
// LOG_ERR("format_and_mount_fs failed (%d)", rc);
// k_msleep(LOG_RESTART_DELAY_MS);
// continue;
// }
// rc = open_log_file(&file, true);
// if (rc < 0) {
// LOG_ERR("open_log_file(new) failed (%d)", rc);
// fs_unmount(&littlefs_mnt);
// k_msleep(LOG_RESTART_DELAY_MS);
// continue;
// }
// first_segment = false;
// } else {
// rc = mount_fs_no_format();
// if (rc < 0) {
// LOG_ERR("mount_fs_no_format failed (%d)", rc);
// k_msleep(LOG_RESTART_DELAY_MS);
// continue;
// }
// rc = open_log_file(&file, false);
// if (rc < 0) {
// LOG_ERR("open_log_file(append) failed (%d)", rc);
// fs_unmount(&littlefs_mnt);
// k_msleep(LOG_RESTART_DELAY_MS);
// continue;
// }
// }
// rc = start_logging_segment(&file, this_segment_ms);
// if (rc < 0) {
// LOG_WRN("Segment %u failed (%d). Waiting %d ms and restarting logging",
// segment_num, rc, LOG_RESTART_DELAY_MS);
// green_on();
// k_msleep(500);
// fs_close(&file);
// fs_unmount(&littlefs_mnt);
// blue_off();
// green_off();
// k_msleep(LOG_RESTART_DELAY_MS);
// /* Do not exit. Next loop iteration remounts and appends. */
// continue;
// }
// rc = fs_seek(&file, 0, FS_SEEK_END);
// if (rc == 0) {
// off_t size = fs_tell(&file);
// LOG_INF("File size after segment %u: %lld bytes",
// segment_num, (long long)size);
// }
// fs_close(&file);
// fs_unmount(&littlefs_mnt);
// if ((k_uptime_get() - total_start_ms) >= TOTAL_LOG_TIME_MS) {
// break;
// }
// LOG_INF("Segment %u complete. Waiting %d ms before restart",
// segment_num, LOG_RESTART_DELAY_MS);
// blue_off();
// k_msleep(LOG_RESTART_DELAY_MS);
// }
// blue_off();
// green_off();
// LOG_INF("Logging session complete. Total records=%u",
// (unsigned int)total_records_logged);
// return 0;
// }
// static int run_transfer(void)
// {
// int rc;
// struct fs_file_t file;
// sensor_sample_t sample;
// bool blink = false;
// rc = mount_fs_no_format();
// if (rc < 0) {
// return rc;
// }
// rc = bluetooth_init();
// if (rc < 0) {
// LOG_ERR("bluetooth_init failed (%d)", rc);
// fs_unmount(&littlefs_mnt);
// return rc;
// }
// while (!ble_is_connected() || !ble_is_mtu_ready()) {
// blink = !blink;
// (void)pwm_set_dt(&pwm_b, pwm_b.period, blink ? 0 : pwm_b.period);
// k_msleep(200);
// }
// blue_off();
// green_on();
// fs_file_t_init(&file);
// rc = fs_open(&file, LOG_FILE_PATH, FS_O_READ);
// if (rc < 0) {
// LOG_ERR("File open for read failed (%d)", rc);
// fs_unmount(&littlefs_mnt);
// return rc;
// }
// while (1) {
// ssize_t r = fs_read(&file, &sample, sizeof(sample));
// if (r < 0) {
// LOG_ERR("fs_read failed (%d)", (int)r);
// fs_close(&file);
// fs_unmount(&littlefs_mnt);
// return (int)r;
// }
// if (r == 0) {
// break;
// }
// if (r != sizeof(sample)) {
// LOG_WRN("Partial record read (%d), stopping transfer", (int)r);
// break;
// }
// ble_send_sample(&sample);
// k_msleep(50);
// }
// fs_close(&file);
// fs_unmount(&littlefs_mnt);
// k_msleep(500);
// rc = bluetooth_shutdown();
// if (rc < 0) {
// LOG_ERR("bluetooth_shutdown failed (%d)", rc);
// return rc;
// }
// green_off();
// blue_off();
// LOG_INF("Transfer complete");
// return 0;
// }
// /* =========================
// * MAIN
// * ========================= */
// int main(void)
// {
// int rc;
// if (!device_is_ready(pwm_g.dev) ||
// !device_is_ready(pwm_b.dev) ||
// !device_is_ready(ext_switch.port) ||
// !device_is_ready(sw1.port)) {
// LOG_ERR("Required device not ready");
// return -ENODEV;
// }
// rc = gpio_pin_configure_dt(&sw1, GPIO_INPUT);
// if (rc < 0) {
// LOG_ERR("Failed to configure SW1 (%d)", rc);
// return rc;
// }
// rc = gpio_pin_configure_dt(&ext_switch, GPIO_INPUT);
// if (rc < 0) {
// LOG_ERR("Failed to configure EXT switch (%d)", rc);
// return rc;
// }
// green_on();
// blue_on();
// k_msleep(1000);
// green_off();
// blue_off();
// while (1) {
// LOG_INF("Press SW1 2x for SYNC, hold SW1 for LOGGING | EXT switch 2x for TRANSFER");
// LOG_INF("Waiting for mode selection...");
// enum mode m = wait_for_mode();
// switch (m) {
// case MODE_SYNC:
// LOG_INF("MODE: SYNC");
// rc = run_sync();
// break;
// case MODE_LOG:
// LOG_INF("MODE: LOGGING");
// rc = run_log();
// break;
// case MODE_TRANSFER:
// LOG_INF("MODE: TRANSFER");
// rc = run_transfer();
// break;
// default:
// LOG_INF("MODE: IDLE");
// rc = 0;
// break;
// }
// if (rc < 0) {
// LOG_ERR("Mode failed (%d)", rc);
// }
// LOG_INF("Returning to idle wait...");
// }
// }
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/pwm.h>
#include <zephyr/fs/fs.h>
#include <zephyr/fs/littlefs.h>
#include <zephyr/storage/flash_map.h>
#include <zephyr/logging/log.h>
#include <string.h>
#include <errno.h>
#include "clock_bt_setup.h"
#include "sensor_fusion.h"
#include "bluetooth_conn.h"
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
/* =========================
* Flash / FS
* ========================= */
#define LFS_PARTITION_ID FLASH_AREA_ID(lfs_partition)
static struct fs_littlefs lfs_cfg = {
.cfg = {
.read_size = 16,
.prog_size = 16,
.cache_size = 64,
.lookahead_size = 64,
.block_cycles = 32,
}
};
static struct fs_mount_t littlefs_mnt = {
.type = FS_LITTLEFS,
.fs_data = &lfs_cfg,
.storage_dev = (void *)LFS_PARTITION_ID,
.mnt_point = "/lfs",
};
/* =========================
* Hardware
* ========================= */
#define LED_G_NODE DT_PATH(pwmleds, led_g)
#define LED_B_NODE DT_PATH(pwmleds, led_b)
static const struct pwm_dt_spec pwm_g = PWM_DT_SPEC_GET(LED_G_NODE);
static const struct pwm_dt_spec pwm_b = PWM_DT_SPEC_GET(LED_B_NODE);
#define EXT_SWITCH_NODE DT_PATH(buttons, ext_switch)
#define SWITCH_NODE DT_PATH(buttons, sw1)
static const struct gpio_dt_spec ext_switch =
GPIO_DT_SPEC_GET(EXT_SWITCH_NODE, gpios);
static const struct gpio_dt_spec sw1 =
GPIO_DT_SPEC_GET(SWITCH_NODE, gpios);
/* =========================
* Buttons
* ========================= */
#define BUTTON_POLL_MS 10
#define BUTTON_DEBOUNCE_MS 40
#define MULTICLICK_TIMEOUT_MS 500
#define LONG_PRESS_MS 1500
/* =========================
* Logging buffer
* ========================= */
#define RECORDS_PER_BUFFER 4 // 4 x 48 bytes = 192 bytes < 2048 heap pool size
#define SYNC_INTERVAL_BYTES 4096
#define MAX_RECORDS 750 /* testing only */
static int counter = 0;
static size_t total_records_logged = 0;
static sensor_sample_t record_buffer[RECORDS_PER_BUFFER];
static size_t buffer_index = 0;
static size_t bytes_since_sync = 0;
/* =========================
* LED Helpers
* ========================= */
static void green_on(void)
{
(void)pwm_set_dt(&pwm_g, pwm_g.period, 0);
}
static void green_off(void)
{
(void)pwm_set_dt(&pwm_g, pwm_g.period, pwm_g.period);
}
static void blue_on(void)
{
(void)pwm_set_dt(&pwm_b, pwm_b.period, 0);
}
static void blue_off(void)
{
(void)pwm_set_dt(&pwm_b, pwm_b.period, pwm_b.period);
}
/* =========================
* Button Helpers
* ========================= */
static bool button_pressed(const struct gpio_dt_spec *btn)
{
int val = gpio_pin_get_dt(btn);
return (val > 0);
}
static void wait_for_release(const struct gpio_dt_spec *btn)
{
while (button_pressed(btn)) {
k_msleep(BUTTON_POLL_MS);
}
}
static uint8_t wait_for_clicks(const struct gpio_dt_spec *btn,
uint8_t min, uint8_t max)
{
uint8_t count = 0;
int64_t last = 0;
bool prev = button_pressed(btn);
/* Start from a known released state */
wait_for_release(btn);
while (1) {
bool now = button_pressed(btn);
if (now && !prev) {
k_msleep(BUTTON_DEBOUNCE_MS);
now = button_pressed(btn);
if (now) {
count++;
last = k_uptime_get();
LOG_INF("Button click count = %u", count);
}
}
if (count >= min) {
if ((k_uptime_get() - last) > MULTICLICK_TIMEOUT_MS) {
return count;
}
}
if (count >= max) {
return count;
}
prev = now;
k_msleep(BUTTON_POLL_MS);
}
}
/* =========================
* Boot Mode
* ========================= */
enum mode {
MODE_IDLE,
MODE_SYNC,
MODE_LOG,
MODE_TRANSFER
};
static enum mode wait_for_mode(void)
{
LOG_INF("Waiting for input: SW1 x2=SYNC, SW1 long press=LOG, EXT x2=TRANSFER");
while (1) {
/* ---------- SW1 handling ---------- */
if (button_pressed(&sw1)) {
k_msleep(BUTTON_DEBOUNCE_MS);
if (button_pressed(&sw1)) {
int64_t press_start = k_uptime_get();
/* Stay here while button is held to determine long press */
while (button_pressed(&sw1)) {
if ((k_uptime_get() - press_start) >= LONG_PRESS_MS) {
LOG_INF("SW1 long press detected");
wait_for_release(&sw1);
return MODE_LOG;
}
k_msleep(BUTTON_POLL_MS);
}
/*
* If we get here, SW1 was a short press.
* Count it as part of a double-click sequence.
*/
uint8_t c = wait_for_clicks(&sw1, 2, 2);
if (c == 2) {
return MODE_SYNC;
}
}
}
/* ---------- EXT switch handling ---------- */
if (button_pressed(&ext_switch)) {
uint8_t c = wait_for_clicks(&ext_switch, 2, 2);
if (c == 2) {
return MODE_TRANSFER;
}
}
k_msleep(10);
}
}
/* =========================
* FS Helpers
* ========================= */
static int mount_fs(void)
{
int rc = fs_mount(&littlefs_mnt);
if (rc == 0) {
LOG_INF("LittleFS mounted");
return 0;
}
LOG_WRN("Mount failed (%d), formatting", rc);
rc = fs_mkfs(FS_LITTLEFS, (uintptr_t)LFS_PARTITION_ID, &lfs_cfg, 0);
if (rc < 0) {
LOG_ERR("fs_mkfs failed (%d)", rc);
return rc;
}
rc = fs_mount(&littlefs_mnt);
if (rc < 0) {
LOG_ERR("Mount after format failed (%d)", rc);
return rc;
}
LOG_INF("LittleFS formatted and mounted");
return 0;
}
static int flush_buffer(struct fs_file_t *file)
{
if (buffer_index == 0) {
return 0;
}
size_t write_size = buffer_index * sizeof(sensor_sample_t);
ssize_t written = fs_write(file, record_buffer, write_size);
if (written < 0) {
LOG_ERR("fs_write failed (%d)", (int)written);
return (int)written;
}
if ((size_t)written != write_size) {
LOG_ERR("fs_write short (%d/%u)", (int)written,
(unsigned int)write_size);
return -EIO;
}
bytes_since_sync += write_size;
buffer_index = 0;
if (bytes_since_sync >= SYNC_INTERVAL_BYTES) {
int rc = fs_sync(file);
if (rc < 0) {
LOG_ERR("fs_sync failed (%d)", rc);
return rc;
}
bytes_since_sync = 0;
counter++;
LOG_INF("Synced to flash");
}
return 0;
}
static int recover_filesystem_no_format(struct fs_file_t *file)
{
int rc;
fs_close(file);
fs_unmount(&littlefs_mnt);
k_msleep(500); // Let things settle before remounting
// rc = fs_mkfs(FS_LITTLEFS, (uintptr_t)LFS_PARTITION_ID, &lfs_cfg, 0);
// if (rc < 0) {
// LOG_ERR("fs_mkfs failed during recovery (%d)", rc);
// return rc;
// }
rc = fs_mount(&littlefs_mnt);
if (rc < 0) {
LOG_ERR("Mount failed during recovery (%d)", rc);
return rc;
}
fs_file_t_init(file);
rc = fs_open(file, "/lfs/imu.bin",
FS_O_CREATE | FS_O_TRUNC | FS_O_RDWR);
if (rc < 0) {
LOG_ERR("File open failed during recovery (%d)", rc);
return rc;
}
buffer_index = 0;
bytes_since_sync = 0;
LOG_WRN("Filesystem recovery complete without formatting");
green_on();
k_msleep(500);
green_off();
return 0;
}
static int recover_filesystem(struct fs_file_t *file)
{
int rc;
fs_close(file);
fs_unmount(&littlefs_mnt);
rc = fs_mkfs(FS_LITTLEFS, (uintptr_t)LFS_PARTITION_ID, &lfs_cfg, 0);
if (rc < 0) {
LOG_ERR("fs_mkfs failed during recovery (%d)", rc);
return rc;
}
rc = fs_mount(&littlefs_mnt);
if (rc < 0) {
LOG_ERR("Mount failed during recovery (%d)", rc);
return rc;
}
fs_file_t_init(file);
rc = fs_open(file, "/lfs/imu.bin",
FS_O_CREATE | FS_O_TRUNC | FS_O_RDWR);
if (rc < 0) {
LOG_ERR("File open failed during recovery (%d)", rc);
return rc;
}
buffer_index = 0;
bytes_since_sync = 0;
LOG_WRN("Filesystem recovery complete");
return 0;
}
/* =========================
* Logging
* ========================= */
static int start_logging(struct fs_file_t *file)
{
int rc;
bool led_state = false;
uint32_t blink_count = 0;
total_records_logged = 0;
buffer_index = 0;
bytes_since_sync = 0;
counter = 0;
while (counter <= MAX_RECORDS) {
sensor_sample_t r;
rc = sensors_read(&r);
if (rc < 0) {
LOG_ERR("sensors_read failed (%d)", rc);
return rc;
}
record_buffer[buffer_index++] = r;
total_records_logged++;
if (buffer_index >= RECORDS_PER_BUFFER) {
rc = flush_buffer(file);
if (rc == -EINVAL) {
LOG_WRN("Write returned -EINVAL; attempting FS recovery");
if (counter == 0) {
rc = recover_filesystem(file);
}
LOG_INF("Logging failed, total records=%u",
(unsigned int)total_records_logged);
rc = recover_filesystem_no_format(file);
if (rc < 0) {
return rc;
}
continue;
}
if (rc < 0) {
return rc;
}
}
if (++blink_count >= 20) {
led_state = !led_state;
(void)pwm_set_dt(&pwm_b, pwm_b.period,
led_state ? 0 : pwm_b.period);
blink_count = 0;
}
k_msleep(20);
}
rc = flush_buffer(file);
if (rc == -EINVAL) {
LOG_WRN("Final flush -EINVAL; attempting FS recovery");
rc = recover_filesystem_no_format(file);
if (rc < 0) {
return rc;
}
} else if (rc < 0) {
return rc;
}
rc = fs_sync(file);
if (rc < 0) {
LOG_ERR("fs_sync failed (%d)", rc);
return rc;
}
LOG_INF("Logging complete, total records=%u",
(unsigned int)total_records_logged);
return 0;
}
/* =========================
* Modes
* ========================= */
static int run_sync(void)
{
int rc = setup_clock();
if (rc < 0) {
LOG_ERR("setup_clock failed (%d)", rc);
return rc;
}
bool state = false;
while (!clock_bt_is_time_synced()) {
state = !state;
(void)pwm_set_dt(&pwm_g, pwm_g.period, state ? 0 : pwm_g.period);
k_msleep(200);
}
green_on();
k_msleep(1000);
rc = shutdown_clock_bt();
if (rc < 0) {
LOG_ERR("shutdown_clock_bt failed (%d)", rc);
return rc;
}
green_off();
return 0;
}
static int run_log(void)
{
int rc;
struct fs_file_t file;
/* Ensure LED state is clean before logging */
green_off();
blue_off();
rc = sensors_init();
if (rc < 0) {
LOG_ERR("sensors_init failed (%d)", rc);
return rc;
}
//format the system before writing to it, to ensure a clean state. This will delete any existing data, but ensures we can log without fs errors.
rc = fs_mkfs(FS_LITTLEFS, (uintptr_t)LFS_PARTITION_ID, &lfs_cfg, 0);
if (rc < 0) {
LOG_ERR("fs_mkfs failed during recovery (%d)", rc);
return rc;
}
LOG_INF("Filesystem formatted for logging");
rc = mount_fs();
if (rc < 0) {
return rc;
}
fs_file_t_init(&file);
// rc = fs_open(&file, "/lfs/imu.bin",
// FS_O_CREATE | FS_O_TRUNC | FS_O_RDWR);
rc = fs_open(&file, "/lfs/imu.bin",
FS_O_CREATE | FS_O_TRUNC | FS_O_RDWR);
if (rc < 0) {
LOG_ERR("File open failed (%d)", rc);
fs_unmount(&littlefs_mnt);
return rc;
}
rc = start_logging(&file);
rc = fs_seek(&file, 0, FS_SEEK_END);
if (rc == 0) {
off_t size = fs_tell(&file);
LOG_INF("Logged file size: %lld bytes", (long long)size);
}
fs_close(&file);
fs_unmount(&littlefs_mnt);
if (rc < 0) {
return rc;
}
blue_off();
green_off();
return 0;
}
static int run_transfer(void)
{
int rc;
struct fs_file_t file;
sensor_sample_t sample;
bool blink = false;
rc = mount_fs();
if (rc < 0) {
return rc;
}
rc = bluetooth_init();
if (rc < 0) {
LOG_ERR("bluetooth_init failed (%d)", rc);
fs_unmount(&littlefs_mnt);
return rc;
}
while (!ble_is_connected() || !ble_is_mtu_ready()) {
blink = !blink;
(void)pwm_set_dt(&pwm_b, pwm_b.period, blink ? 0 : pwm_b.period);
k_msleep(200);
}
blue_off();
green_on();
fs_file_t_init(&file);
rc = fs_open(&file, "/lfs/imu.bin", FS_O_READ);
if (rc < 0) {
LOG_ERR("File open for read failed (%d)", rc);
fs_unmount(&littlefs_mnt);
return rc;
}
while (1) {
ssize_t r = fs_read(&file, &sample, sizeof(sample));
if (r < 0) {
LOG_ERR("fs_read failed (%d)", (int)r);
fs_close(&file);
fs_unmount(&littlefs_mnt);
return (int)r;
}
if (r == 0) {
break;
}
if (r != sizeof(sample)) {
LOG_WRN("Partial record read (%d), stopping transfer", (int)r);
break;
}
ble_send_sample(&sample);
k_msleep(50);
}
fs_close(&file);
fs_unmount(&littlefs_mnt);
/* Let final BLE packets drain */
k_msleep(500);
rc = bluetooth_shutdown();
if (rc < 0) {
LOG_ERR("bluetooth_shutdown failed (%d)", rc);
return rc;
}
green_off();
blue_off();
LOG_INF("Transfer complete");
return 0;
}
/* =========================
* MAIN
* ========================= */
int main(void)
{
int rc;
if (!device_is_ready(pwm_g.dev) ||
!device_is_ready(pwm_b.dev) ||
!device_is_ready(ext_switch.port) ||
!device_is_ready(sw1.port)) {
LOG_ERR("Required device not ready");
return -ENODEV;
}
rc = gpio_pin_configure_dt(&sw1, GPIO_INPUT);
if (rc < 0) {
LOG_ERR("Failed to configure SW1 (%d)", rc);
return rc;
}
rc = gpio_pin_configure_dt(&ext_switch, GPIO_INPUT);
if (rc < 0) {
LOG_ERR("Failed to configure EXT switch (%d)", rc);
return rc;
}
// POWER ON STATE OF Device
green_on();
blue_on();
k_msleep(1000);
green_off();
blue_off();
while (1) {
LOG_INF("Press SW1 2x for SYNC, hold SW1 for LOGGING | EXT switch 2x for TRANSFER");
LOG_INF("Waiting for mode selection...");
enum mode m = wait_for_mode();
switch (m) {
case MODE_SYNC:
LOG_INF("MODE: SYNC");
rc = run_sync();
break;
case MODE_LOG:
LOG_INF("MODE: LOGGING");
rc = run_log();
break;
case MODE_TRANSFER:
LOG_INF("MODE: TRANSFER");
rc = run_transfer();
break;
default:
LOG_INF("MODE: IDLE");
rc = 0;
break;
}
if (rc < 0) {
LOG_ERR("Mode failed (%d)", rc);
}
LOG_INF("Returning to idle wait...");
}
}
# LOGGING CONFIGURATION CONFIG_USE_SEGGER_RTT=y CONFIG_RTT_CONSOLE=y CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=8192 CONFIG_SEGGER_RTT_BUFFER_SIZE_DOWN=16 CONFIG_HEAP_MEM_POOL_SIZE=2048 # SENSOR CONFIGURATION CONFIG_SPI=y CONFIG_I2C=y CONFIG_SENSOR=y CONFIG_IIS2MDC=y CONFIG_ISM330DHCX=y # SWITCH CONFIGURATION CONFIG_GPIO=y #PWM CONFIGURATION CONFIG_PWM=y # FLASH CONFIGURATION CONFIG_FLASH=y CONFIG_FLASH_MAP=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_SPI_NOR=y # FILE SYSTEM CONFIGURATION CONFIG_FILE_SYSTEM=y CONFIG_FILE_SYSTEM_LITTLEFS=y CONFIG_FILE_SYSTEM_MKFS=y # BLUETOOTH CONFIGURATION CONFIG_BT=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="GAIT_BOARD_0006" # CONFIG_BT_MAX_CONN=1 CONFIG_BT_GATT_CLIENT=y CONFIG_BT_SMP=y # optional (only if you want pairing) CONFIG_BT_GATT_DM=y CONFIG_BT_CTS_CLIENT=y # CONFIG_BT_GATT_NOTIFY=y CONFIG_BT_L2CAP_TX_BUF_COUNT=10 CONFIG_BT_BUF_ACL_TX_COUNT=10 CONFIG_BT_USER_DATA_LEN_UPDATE=y CONFIG_BT_BUF_ACL_TX_SIZE=251 CONFIG_BT_BUF_ACL_RX_SIZE=251 CONFIG_BT_L2CAP_TX_MTU=247 CONFIG_BT_PHY_UPDATE=y CONFIG_BT_DATA_LEN_UPDATE=y # STACK CONFIGURATION CONFIG_MAIN_STACK_SIZE=16384 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 CONFIG_ISR_STACK_SIZE=2048 # LOGGING CONFIGURATION CONFIG_LOG=y CONFIG_LOG_MODE_DEFERRED=n CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_SPI_LOG_LEVEL_INF=y CONFIG_FLASH_LOG_LEVEL_INF=y # POWER CONFIGURATION # used for partition manager and littlefs (to set up a partition inside the external flash) CONFIG_PARTITION_MANAGER_ENABLED=y CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK=y CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
external_flash: address: 0x0 size: 0x02000000 # 32MB region: external_flash device: spi_flash2 # <-- must match DT node label lfs_partition: address: 0x00000000 size: 0x01C00000 # 28MB region: external_flash device: spi_flash2
/dts-v1/;
#include <nordic/nrf52840_qfaa.dtsi>
// #include "gait_board_NRF52840-pinctrl.dtsi"
/ {
model = "ProFormIQ, NRF52840-QFAA";
compatible = "NordicSemiConductor,gait-board-NRF52840";
chosen {
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,code-partition = &slot0_partition;
nordic,pm-ext-flash = &spi_flash2;
};
// leds {
// compatible = "gpio-leds";
// led_g {
// label = "led_g";
// gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
// };
// led_b {
// label = "led_b";
// gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
// };
// led_r {
// label = "led_r";
// gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>;
// };
// };
pwmleds {
compatible = "pwm-leds";
// led_r: led_r {
// pwms = <&pwm0 0 PWM_HZ(1000) PWM_POLARITY_INVERTED>;
// };
led_b: led_b {
pwms = <&pwm0 1 PWM_HZ(1000) PWM_POLARITY_INVERTED>;
};
led_g: led_g {
pwms = <&pwm0 2 PWM_HZ(1000) PWM_POLARITY_INVERTED>;
};
};
buttons {
compatible = "gpio-keys";
sw1: sw1 {
label = "sw1";
gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
};
ext_switch:ext_switch {
label = "ext_switch";
gpios = <&gpio0 7 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
};
};
};
/* =========================
* Internal Flash Partitions
* ========================= */
&flash0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
boot_partition: partition@0 {
label = "mcuboot";
reg = <0x00000000 DT_SIZE_K(48)>;
};
slot0_partition: partition@c000 {
label = "image-0";
reg = <0x0000c000 DT_SIZE_K(472)>;
};
slot1_partition: partition@82000 {
label = "image-1";
reg = <0x00082000 DT_SIZE_K(472)>;
};
storage_partition: partition@f8000 {
label = "storage";
reg = <0x000f8000 DT_SIZE_K(32)>;
};
};
};
&gpiote {
status = "okay";
};
&gpio0 {
status = "okay";
};
&gpio1 {
status = "okay";
};
&spi0 {
status = "okay";
// CS index 0 = ISM330
cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi0_default>;
pinctrl-1 = <&spi0_sleep>;
pinctrl-names = "default", "sleep";
/* =========================
* IMU (existing, unchanged)
* ========================= */
ism330: ism330dhcx@0 {
compatible = "st,ism330dhcx";
reg = <0>; /* CS index 0 */
spi-max-frequency = <10000000>;
drdy-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
int-pin = <1>;
accel-odr = <4>;
accel-range = <4>;
gyro-odr = <4>;
gyro-range = <500>;
};
};
&pinctrl {
spi0_default: spi0_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 9)>,
<NRF_PSEL(SPIM_MOSI, 0, 11)>,
<NRF_PSEL(SPIM_MISO, 0, 12)>;
};
};
spi0_sleep: spi0_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 9)>;
};
};
i2c1_default: i2c1_default {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 0, 13)>, <NRF_PSEL(TWIM_SCL, 0, 14)>;
};
};
i2c1_sleep: i2c1_sleep {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 0, 13)>;
};
};
// pwm0_default: pwm0_default {
// group1 {
// psels = <NRF_PSEL(PWM_OUT0, 0, 31)>,
// <NRF_PSEL(PWM_OUT1, 0, 30)>,
// <NRF_PSEL(PWM_OUT2, 0, 29)>;
// };
// };
pwm0_default: pwm0_default {
group1 {
psels = <NRF_PSEL(PWM_OUT1, 0, 30)>,
<NRF_PSEL(PWM_OUT2, 0, 29)>;
};
};
pwm0_sleep: pwm0_sleep {
group1 {
psels = <NRF_PSEL(PWM_OUT1, 0, 30)>,
<NRF_PSEL(PWM_OUT2, 0, 29)>;
low-power-enable;
};
};
spi2_default: spi2_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 0, 19)>,
<NRF_PSEL(SPIM_MOSI, 0, 21)>,
<NRF_PSEL(SPIM_MISO, 0, 22)>;
};
};
spi2_sleep: spi2_sleep {
group1 {
psels = <
NRF_PSEL(SPIM_SCK, 0, 19)
NRF_PSEL(SPIM_MOSI, 0, 21)
NRF_PSEL(SPIM_MISO, 0, 22)
>;
low-power-enable;
};
};
};
&adc {
status = "okay";
battery_voltage: battery_voltage {
compatible = "voltage-divider";
io-channels = <&adc 0>; /* AIN0 */
label = "BATTERY_VOLTAGE";
/* Replace with your actual resistor values */
output-ohms = <100>; /* Rbottom */
full-ohms = <570>; /* Rtop + Rbottom */
};
};
&i2c1 {
status = "okay";
pinctrl-0 = <&i2c1_default>;
pinctrl-1 = <&i2c1_sleep>;
pinctrl-names = "default", "sleep";
/* ISS2MDCTR – Magnetometer (open-drain INT) */
iis2mdc: iis2mdc@1e {
compatible = "st,iis2mdc";
reg = <0x1e>;
/* DRDY is open-drain, active-low */
drdy-gpios = <&gpio0 17 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
};
/*DS3231 RTC Real time clock */
ds3231: ds3231@68 {
compatible = "maxim,ds3231";
reg = <0x68>;
// status = "okay";
};
};
&pwm0 {
status = "okay";
pinctrl-0 = <&pwm0_default>;
pinctrl-1 = <&pwm0_sleep>;
pinctrl-names = "default", "sleep";
};
&qspi {
status = "disabled";
};
&spi2 {
status = "okay";
pinctrl-0 = <&spi2_default>;
pinctrl-1 = <&spi2_sleep>;
pinctrl-names = "default", "sleep";
cs-gpios = <
&gpio0 20 GPIO_ACTIVE_LOW
>;
spi_flash2: flash@0 {
compatible = "jedec,spi-nor";
reg = <0>; /* MUST be 0 */
label = "SPI_FLASH";
spi-max-frequency = <2000000>;
jedec-id = [ EF 40 19 ];
size = <0x02000000>;
// has-dpd;
// t-enter-dpd = <3000>;
// t-exit-dpd = <3000>;
// partitions {
// compatible = "fixed-partitions";
// #address-cells = <1>;
// #size-cells = <1>;
// lfs_partition: partition@0 {
// label = "lfs";
// reg = <0x00000000 0x01C00000>; /* 28 MB */
// };
// };
};
};