From 356859fc9c0379ffe5655437719255be0750cdcf Mon Sep 17 00:00:00 2001 From: Oliver Bagge Date: Mon, 8 Sep 2025 16:48:05 +0200 Subject: [PATCH 1/5] Set SPI speed to 32MHz --- .../SD_Card_Manager/SD_Card_Manager.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/SD_Card/SD_Card_Manager/SD_Card_Manager.cpp b/src/SD_Card/SD_Card_Manager/SD_Card_Manager.cpp index 9620a2eb..24e84d43 100644 --- a/src/SD_Card/SD_Card_Manager/SD_Card_Manager.cpp +++ b/src/SD_Card/SD_Card_Manager/SD_Card_Manager.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "openearable_common.h" @@ -231,6 +232,29 @@ int SDCardManager::mount() { } } + // Set SPI bus frequency to 32MHz + nrf_spim_frequency_set(NRF_SPIM4, NRF_SPIM_FREQ_32M); + + // Log SPI bus frequency (configured max frequency from device tree) + uint32_t spi_max_freq = DT_PROP(DT_NODELABEL(spi4), max_frequency); + LOG_INF("SD card SPI bus frequency: %d Hz (max configured)", spi_max_freq); + + // Log actual SPI bus frequency + uint32_t actual_hz; + switch(nrf_spim_frequency_get(NRF_SPIM4)) { + case NRF_SPIM_FREQ_125K: actual_hz = 125000; break; + case NRF_SPIM_FREQ_250K: actual_hz = 250000; break; + case NRF_SPIM_FREQ_500K: actual_hz = 500000; break; + case NRF_SPIM_FREQ_1M: actual_hz = 1000000; break; + case NRF_SPIM_FREQ_2M: actual_hz = 2000000; break; + case NRF_SPIM_FREQ_4M: actual_hz = 4000000; break; + case NRF_SPIM_FREQ_8M: actual_hz = 8000000; break; + case NRF_SPIM_FREQ_16M: actual_hz = 16000000; break; + case NRF_SPIM_FREQ_32M: actual_hz = 32000000; break; + default: actual_hz = 0; break; + } + LOG_INF("Effective SPI frequency: %d Hz", actual_hz); + ret = k_mutex_lock(&m_sem_sd_mngr_oper_ongoing, K_FOREVER); if (ret) { k_mutex_unlock(&m_sem_sd_mngr_oper_ongoing); From 63fb0e4259afaf9b312710ecd22d24b1b277fe46 Mon Sep 17 00:00:00 2001 From: Oliver Bagge Date: Mon, 8 Sep 2025 16:59:55 +0200 Subject: [PATCH 2/5] fix name of board in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ecb5c15..47f6a05c 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ - In the **APPLICATIONS** section of the nRF Connect extension tab: - Select the `open-earable-2` application - Click **"+ Add build configuration"** to set up a new build - - Select the SDK version 3.0.1, toolchain version 3.0.1, and `open-earable-2/nrf5340/cpuapp` as board target + - Select the SDK version 3.0.1, toolchain version 3.0.1, and `openearable_v2/nrf5340/cpuapp` as board target - To build **with FOTA** (firmware over-the-air update functionality): - Leave the `Base configuration files (Kconfig fragments)` dropdown empty - as `Extra CMAKE arguments` set `-DFILE_SUFFIX="fota"` From b233db50c27e1458fb514076f9a33d642e563faa Mon Sep 17 00:00:00 2001 From: Oliver Bagge Date: Fri, 26 Sep 2025 12:31:04 +0200 Subject: [PATCH 3/5] add batched calls to fs_sync --- .../openearable_v2_nrf5340_cpuapp_common.dts | 1 + src/SD_Card/SDLogger/SDLogger.cpp | 22 +++++++++++++++++++ src/SD_Card/SDLogger/SDLogger.h | 7 ++++++ .../SD_Card_Manager/SD_Card_Manager.cpp | 2 +- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/boards/teco/openearable_v2/openearable_v2_nrf5340_cpuapp_common.dts b/boards/teco/openearable_v2/openearable_v2_nrf5340_cpuapp_common.dts index d3796b69..ca836918 100644 --- a/boards/teco/openearable_v2/openearable_v2_nrf5340_cpuapp_common.dts +++ b/boards/teco/openearable_v2/openearable_v2_nrf5340_cpuapp_common.dts @@ -231,6 +231,7 @@ &spi4 { compatible = "nordic,nrf-spim"; status = "okay"; + max-frequency = <32000000>; cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>,<&gpio1 1 GPIO_ACTIVE_LOW>; pinctrl-0 = <&spi4_default>; diff --git a/src/SD_Card/SDLogger/SDLogger.cpp b/src/SD_Card/SDLogger/SDLogger.cpp index 35f93c2b..4fc0089d 100644 --- a/src/SD_Card/SDLogger/SDLogger.cpp +++ b/src/SD_Card/SDLogger/SDLogger.cpp @@ -93,6 +93,9 @@ void sd_listener_callback(const struct zbus_channel *chan) state_indicator.set_sd_state(SD_FAULT); LOG_ERR("SD card removed mid recording. Stop recording."); + (void)sdlogger.flush(); + (void)sdlogger.sd_card->sync(); + (void)sdlogger.sd_card->close_file(); // sdlogger.end(); sdlogger.is_open = false; @@ -126,8 +129,27 @@ void SDLogger::sensor_sd_task() { ring_buf_get_claim(&ring_buffer, &data, SD_BLOCK_SIZE); bytes_read = sdlogger.sd_card->write((char*)data, &write_size, false); + uint64_t end_us = micros(); ring_buf_get_finish(&ring_buffer, bytes_read); + if (bytes_read > 0) { + sdlogger.unsynced_bytes += bytes_read; + uint64_t now = end_us; + bool size_gate = (sdlogger.unsynced_bytes >= SYNC_EVERY_BYTES); + bool time_gate = ((now - sdlogger.last_sync_us) >= (uint64_t)SYNC_EVERY_MS * 1000); + + // Optional: only sync when ring is not near full to reduce contention + if ((size_gate || time_gate) && ring_buf_size_get(&ring_buffer) < (BUFFER_SIZE / 4)) { + int sret = sdlogger.sd_card->sync(); + if (sret == 0) { + sdlogger.unsynced_bytes = 0; + sdlogger.last_sync_us = now; + } else { + LOG_WRN("fs_sync deferred: %d", sret); + } + } + } + //k_mutex_unlock(&write_mutex); //fill -= bytes_read; diff --git a/src/SD_Card/SDLogger/SDLogger.h b/src/SD_Card/SDLogger/SDLogger.h index 4a82dcc7..74ff5572 100644 --- a/src/SD_Card/SDLogger/SDLogger.h +++ b/src/SD_Card/SDLogger/SDLogger.h @@ -54,6 +54,13 @@ class SDLogger { friend void sd_listener_callback(const struct zbus_channel *chan); + // Batching controls + size_t unsynced_bytes = 0; + uint64_t last_sync_us = 0; + // Tunables + static constexpr size_t SYNC_EVERY_BYTES = 32 * 1024; // 32 KB + static constexpr uint32_t SYNC_EVERY_MS = 500; // 0.5 s + public: SDLogger(); ~SDLogger(); diff --git a/src/SD_Card/SD_Card_Manager/SD_Card_Manager.cpp b/src/SD_Card/SD_Card_Manager/SD_Card_Manager.cpp index 24e84d43..4a45e50d 100644 --- a/src/SD_Card/SD_Card_Manager/SD_Card_Manager.cpp +++ b/src/SD_Card/SD_Card_Manager/SD_Card_Manager.cpp @@ -677,7 +677,7 @@ int SDCardManager::rm(std::string path) { } int SDCardManager::sync() { - if (!this->mounted) { + if (!this->mounted || !this->tracked_file.is_open) { return -ENODEV; } From 8d73c5fa0e6c0883e392d512434d851296c7077f Mon Sep 17 00:00:00 2001 From: Oliver Bagge Date: Fri, 26 Sep 2025 12:37:29 +0200 Subject: [PATCH 4/5] forgot some changes in SDLogger for last commit --- src/SD_Card/SDLogger/SDLogger.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/SD_Card/SDLogger/SDLogger.cpp b/src/SD_Card/SDLogger/SDLogger.cpp index 4fc0089d..eebf55b5 100644 --- a/src/SD_Card/SDLogger/SDLogger.cpp +++ b/src/SD_Card/SDLogger/SDLogger.cpp @@ -253,6 +253,9 @@ int SDLogger::begin(const std::string& filename) { k_poll_signal_raise(&logger_sig, 0); + unsynced_bytes = 0; + last_sync_us = micros(); + return 0; } @@ -306,13 +309,15 @@ int SDLogger::write_sensor_data(const sensor_data& msg) { int SDLogger::flush() { uint32_t bytes_read; uint8_t * data; - size_t write_size = SD_BLOCK_SIZE; - uint32_t fill = ring_buf_size_get(&ring_buffer); + if (fill == 0) return 0; - ring_buf_get_claim(&ring_buffer, &data, fill); + // Claim exactly what’s available + uint32_t claimed = ring_buf_get_claim(&ring_buffer, &data, fill); + if (claimed == 0) return 0; - bytes_read = sd_card->write((char*)ring_buffer.buffer, &write_size, false); + size_t write_size = claimed; + bytes_read = sd_card->write((char*)data, &write_size, false); ring_buf_get_finish(&ring_buffer, bytes_read); @@ -344,7 +349,10 @@ int SDLogger::end() { LOG_ERR("Failed to flush file buffer."); return ret; } - + int sret = sd_card->sync(); + if (sret) { + LOG_WRN("Final fs_sync failed: %d", sret); + } LOG_INF("Close File ...."); LOG_DBG("Max buffer fill: %d bytes", count_max_buffer_fill); From 126b0320f4cb164b467b1876f201b7d28e60f0fe Mon Sep 17 00:00:00 2001 From: Oliver Bagge Date: Mon, 1 Dec 2025 16:45:13 +0100 Subject: [PATCH 5/5] fix merge conflict in README.md --- README.md | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6a7f9416..9a4036e5 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,16 @@ ## Table of Contents -1. [Setup](#setup) - -2. [Battery States](#battery-states) - -3. [Connection States](#connection-states) - -4. [SD Card](#sd-card) - -5. [Citing](#citing) +- [OpenEarable 2 - Firmware](#openearable-2---firmware) + - [Table of Contents](#table-of-contents) + - [Setup](#setup) + - [Battery States](#battery-states) + - [Charging States](#charging-states) + - [Discharging States](#discharging-states) + - [Connection States](#connection-states) + - [SD Card](#sd-card) + - [File Parsing](#file-parsing) + - [Citing](#citing) ## Setup @@ -51,15 +52,9 @@ 8. **Configure the Application Build** - If not already open, navigate to the nrfConnect extension tab in VSCode. - In the **APPLICATIONS** section of the nRF Connect extension tab: -<<<<<<< HEAD - - Select the `open-earable-2` application - - Click **"+ Add build configuration"** to set up a new build - - Select the SDK version 3.0.1, toolchain version 3.0.1, and `openearable_v2/nrf5340/cpuapp` as board target -======= - Select the `open-earable-2` application. - Click **"+ Add build configuration"** to set up a new build. - Select the SDK version 3.0.1, toolchain version 3.0.1, and `open-earable-2/nrf5340/cpuapp` as board target. ->>>>>>> 56d72efc73b703a45a87936032c0b69fb77ac90d - To build **with FOTA** (firmware over-the-air update functionality): - Leave the `Base configuration files (Kconfig fragments)` dropdown empty. - as `Extra CMAKE arguments` set `-DFILE_SUFFIX="fota"`.