diff --git a/firmware/boards/nrf52840dk_nrf52840.conf b/firmware/boards/nrf52840dk_nrf52840.conf index 76eeb5d..332c42f 100644 --- a/firmware/boards/nrf52840dk_nrf52840.conf +++ b/firmware/boards/nrf52840dk_nrf52840.conf @@ -1 +1,2 @@ -CONFIG_NRFX_POWER=y \ No newline at end of file +CONFIG_NRFX_POWER=y +CONFIG_BT=n \ No newline at end of file diff --git a/firmware/boards/nrf52840dk_nrf52840.overlay b/firmware/boards/nrf52840dk_nrf52840.overlay index 6a4d353..06c5ea2 100644 --- a/firmware/boards/nrf52840dk_nrf52840.overlay +++ b/firmware/boards/nrf52840dk_nrf52840.overlay @@ -6,6 +6,7 @@ status-led = &led2; buzzer-button = &button0; audio-i2s = &i2s0; + audio-amp-en = &audio_amp_en; usb-uart = &cdc_acm_uart0; qspi-flash = &mx25r64; }; @@ -17,6 +18,14 @@ zephyr,user { usb-detect-gpios = <&gpio1 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; }; + + amp { + compatible = "gpio-leds"; + audio_amp_en: audio_amp_en { + gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + label = "Amplifier Shudown Pin"; + }; + }; }; &usbd { @@ -52,4 +61,17 @@ pinctrl-0 = <&i2s0_default>; pinctrl-1 = <&i2s0_sleep>; pinctrl-names = "default", "sleep"; -}; \ No newline at end of file +}; + +// &uart0 { status = "disabled"; }; +&i2c0 { status = "disabled"; }; +&spi1 { status = "disabled"; }; +&spi3 { status = "disabled"; }; +&adc { status = "disabled"; }; +&nfct { status = "disabled"; }; +&temp { status = "disabled"; }; +&pwm0 { status = "disabled"; }; +&radio { status = "disabled"; }; +&ieee802154 { status = "disabled"; }; +&bt_hci_sdc { status = "disabled"; }; +&cryptocell { status = "disabled"; }; \ No newline at end of file diff --git a/firmware/prj.conf b/firmware/prj.conf index 0720eba..5ed4f55 100644 --- a/firmware/prj.conf +++ b/firmware/prj.conf @@ -42,5 +42,10 @@ CONFIG_NRFX_I2S=y # --- Random & HW Info (für Audio-File-Auswahl) --- CONFIG_HWINFO=y -CONFIG_ENTROPY_GENERATOR=y -CONFIG_CRC=y \ No newline at end of file +CONFIG_CRC=y + +# --- Unbenutze Features --- +CONFIG_ADC=n +CONFIG_I2C=n +CONFIG_SPI=n +CONFIG_PWM=n \ No newline at end of file diff --git a/firmware/src/audio.c b/firmware/src/audio.c index cdd8012..9292a46 100644 --- a/firmware/src/audio.c +++ b/firmware/src/audio.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -29,13 +30,42 @@ K_SEM_DEFINE(audio_ready_sem, 0, 1); #error "Audio I2S alias not defined in devicetree" #endif +#define AUDIO_AMP_ENABLE_NODE DT_ALIAS(audio_amp_en) +#if !DT_NODE_EXISTS(AUDIO_AMP_ENABLE_NODE) +#error "Audio Amplifier Enable alias not defined in devicetree" +#endif + static const struct device *const i2s_dev = DEVICE_DT_GET(I2S_NODE); +static const struct gpio_dt_spec amp_en_dev = GPIO_DT_SPEC_GET(AUDIO_AMP_ENABLE_NODE, gpios); + + static volatile bool abort_playback = false; static char next_random_filename[64] = {0}; static uint32_t audio_file_count = 0; static char cached_404_path[] = "/lfs/sys/404"; +void i2s_suspend(void) +{ + LOG_DBG("Suspending I2S interface for power saving"); + i2s_trigger(i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DROP); + + /* Nutzt jetzt die korrekte Spezifikation */ + gpio_pin_set_dt(&_en_dev, 0); + + pm_device_action_run(i2s_dev, PM_DEVICE_ACTION_SUSPEND); +} + +void i2s_resume(void) +{ + LOG_DBG("Resuming I2S interface"); + + /* Zuerst Pin auf High, dann Hardware wecken */ + gpio_pin_set_dt(&_en_dev, 1); + + pm_device_action_run(i2s_dev, PM_DEVICE_ACTION_RESUME); +} + void audio_refresh_file_count(void) { struct fs_dir_t dirp; @@ -142,6 +172,7 @@ void audio_thread(void *arg1, void *arg2, void *arg3) { LOG_DBG("Audio thread started"); k_sem_take(&audio_ready_sem, K_FOREVER); + i2s_suspend(); /* Ersten zufälligen Dateinamen beim Booten vorab cachen */ get_random_file(next_random_filename, sizeof(next_random_filename)); @@ -152,9 +183,8 @@ void audio_thread(void *arg1, void *arg2, void *arg3) { if (k_msgq_get(&audio_play_msgq, &filename, K_FOREVER) == 0) { - fs_pm_flash_resume(); - abort_playback = false; + i2s_resume(); /* 2. Datei bestimmen (aus Cache oder synchron als Fallback) */ if (filename[0] == '\0') @@ -178,7 +208,7 @@ void audio_thread(void *arg1, void *arg2, void *arg3) struct fs_file_t file; fs_file_t_init(&file); - if (fs_open(&file, filename, FS_O_READ) < 0) + if (fs_pm_open(&file, filename, FS_O_READ) < 0) { LOG_ERR("Failed to open %s", filename); continue; @@ -284,10 +314,10 @@ void audio_thread(void *arg1, void *arg2, void *arg3) } } - fs_close(&file); - fs_pm_flash_suspend(); + fs_pm_close(&file); if (k_msgq_num_used_get(&audio_play_msgq) == 0) { + i2s_suspend(); io_status(false); } @@ -325,6 +355,19 @@ int audio_init(void) if (ret < 0) return ret; + if (!gpio_is_ready_dt(&_en_dev)) { + LOG_DBG("Amplifier enable GPIO device not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&_en_dev, GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + LOG_ERR("Failed to configure amplifier enable GPIO: %d", ret); + return ret; + } + + gpio_pin_configure_dt(&_en_dev, 0); + audio_refresh_file_count(); LOG_INF("Audio initialized: %u bits, %u.%03u kHz", config.word_size, config.frame_clk_freq / 1000, config.frame_clk_freq % 1000); return 0; diff --git a/firmware/src/fs.c b/firmware/src/fs.c index f4d5626..7008996 100644 --- a/firmware/src/fs.c +++ b/firmware/src/fs.c @@ -79,16 +79,19 @@ int fs_pm_flash_resume(void) int fs_pm_open(struct fs_file_t *file, const char *path, fs_mode_t mode) { + LOG_DBG("PM Opening file '%s' with mode 0x%02x", path, mode); + fs_pm_flash_resume(); int rc = fs_open(file, path, mode); - if (rc == 0) + if (rc < 0) { - fs_pm_flash_resume(); + fs_pm_flash_suspend(); } return rc; } int fs_pm_close(struct fs_file_t *file) { + LOG_DBG("PM Closing file"); int rc = fs_close(file); if (rc == 0) { @@ -99,20 +102,44 @@ int fs_pm_close(struct fs_file_t *file) int fs_pm_opendir(struct fs_dir_t *dirp, const char *path) { + LOG_DBG("PM Opening directory '%s'", path); + fs_pm_flash_resume(); int rc = fs_opendir(dirp, path); - if (rc == 0) + if (rc < 0) { - fs_pm_flash_resume(); + fs_pm_flash_suspend(); } return rc; } int fs_pm_closedir(struct fs_dir_t *dirp) { + LOG_DBG("PM Closing directory"); int rc = fs_closedir(dirp); if (rc == 0) { fs_pm_flash_suspend(); } return rc; +} + +int fs_pm_unlink(const char *path) +{ + LOG_DBG("PM Unlinking file '%s'", path); + fs_pm_flash_resume(); + int rc = fs_unlink(path); + if (rc < 0) + { + fs_pm_flash_suspend(); + } + return rc; +} + +int fs_pm_statvfs(const char *path, struct fs_statvfs *stat) +{ + LOG_DBG("PM Getting filesystem stats for '%s'", path); + fs_pm_flash_resume(); + int rc = fs_statvfs(path, stat); + fs_pm_flash_suspend(); + return rc; } \ No newline at end of file diff --git a/firmware/src/fs.h b/firmware/src/fs.h index 272d19e..14f7582 100644 --- a/firmware/src/fs.h +++ b/firmware/src/fs.h @@ -18,9 +18,54 @@ int fs_pm_flash_suspend(void); */ int fs_pm_flash_resume(void); - +/** + * @brief Wrapper around fs_open that handles power management for the flash + * Resumes the flash before opening and suspends it if opening fails + * @param file Pointer to fs_file_t structure to be initialized + * @param path Path to the file to open + * @param mode Open flags (e.g. FS_O_READ, FS_O_WRITE) + * @return 0 on success, negative error code on failure + */ int fs_pm_open(struct fs_file_t *file, const char *path, fs_mode_t mode); + +/** + * @brief Wrapper around fs_close that handles power management for the flash + * Resumes the flash after closing and suspends it if closing fails + * @param file Pointer to fs_file_t structure to be closed + * @return 0 on success, negative error code on failure + */ int fs_pm_close(struct fs_file_t *file); + +/** + * @brief Wrapper around fs_opendir that handles power management for the flash + * Resumes the flash before opening and suspends it if opening fails + * @param dirp Pointer to fs_dir_t structure to be initialized + * @param path Path to the directory to open + * @return 0 on success, negative error code on failure + */ int fs_pm_opendir(struct fs_dir_t *dirp, const char *path); + +/** + * @brief Wrapper around fs_closedir that handles power management for the flash + * Resumes the flash after closing and suspends it if closing fails + * @param dirp Pointer to fs_dir_t structure to be closed + * @return 0 on success, negative error code on failure + */ int fs_pm_closedir(struct fs_dir_t *dirp); + +/** + * @brief Unlinks (deletes) a file, ensuring the flash is active during the operation + * @param path Path to the file to unlink + * @return 0 on success, negative error code on failure + */ +int fs_pm_unlink(const char *path); + +/** + * @brief Wrapper around fs_statvfs that handles power management for the flash + * Resumes the flash before getting stats and suspends it afterwards + * @param path Path to the filesystem to get stats for + * @param stat Pointer to fs_statvfs structure to be filled with stats + * @return 0 on success, negative error code on failure + */ +int fs_pm_statvfs(const char *path, struct fs_statvfs *stat); #endif // FS_H \ No newline at end of file diff --git a/firmware/src/protocol.c b/firmware/src/protocol.c index 7ebce5f..e26fcc5 100644 --- a/firmware/src/protocol.c +++ b/firmware/src/protocol.c @@ -66,7 +66,7 @@ int send_info() { char info[112]; struct fs_statvfs stat; - int rc = fs_statvfs("/lfs", &stat); + int rc = fs_pm_statvfs("/lfs", &stat); if (rc) { LOG_ERR("Failed to get filesystem stats: %d", rc); @@ -87,7 +87,7 @@ int put_binary_file(const char *filename, ssize_t filesize, uint32_t expected_cr size_t accumulated = 0; fs_file_t_init(&file); - fs_unlink(filename); + fs_pm_unlink(filename); LOG_DBG("Opening file '%s' for writing (expected size: %zd bytes, expected CRC32: 0x%08x)", filename, filesize, expected_crc32); rc = fs_pm_open(&file, filename, FS_O_CREATE | FS_O_WRITE); if (rc < 0)