From a2871a193bd026dd3a980022e1ca7864bd0f8058 Mon Sep 17 00:00:00 2001 From: Aaro Saila Date: Tue, 13 Jan 2026 14:49:35 +0200 Subject: [PATCH] ukkonooa and frequency slider --- .clangd | 6 ++ main/CMakeLists.txt | 5 +- main/buzzer.c | 84 +++++++++++++++++++++++++ main/esp-pwm.c | 61 ++++++------------- main/freq_slider.c | 40 ++++++++++++ main/headers/arraylen.h | 6 ++ main/headers/buzzer.h | 14 +++++ main/headers/freq_slider.h | 6 ++ main/headers/un.h | 23 +++++++ main/un.c | 122 +++++++++++++++++++++++++++++++++++++ sdkconfig | 24 ++++---- 11 files changed, 335 insertions(+), 56 deletions(-) create mode 100644 .clangd create mode 100644 main/buzzer.c create mode 100644 main/freq_slider.c create mode 100644 main/headers/arraylen.h create mode 100644 main/headers/buzzer.h create mode 100644 main/headers/freq_slider.h create mode 100644 main/headers/un.h create mode 100644 main/un.c diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..1b2d221 --- /dev/null +++ b/.clangd @@ -0,0 +1,6 @@ +CompileFlags: + Remove: [ + '-fstrict-volatile-bitfields', + '-fno-tree-switch-conversion', + '-fno-shrink-wrap' + ] diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index b7a7f84..dad0751 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,3 @@ -idf_component_register(SRCS "esp-pwm.c" - INCLUDE_DIRS ".") +idf_component_register(SRCS "esp-pwm.c" "buzzer.c" "un.c" "freq_slider.c" + INCLUDE_DIRS "." "./headers" + ) diff --git a/main/buzzer.c b/main/buzzer.c new file mode 100644 index 0000000..3b47bb9 --- /dev/null +++ b/main/buzzer.c @@ -0,0 +1,84 @@ +#include +#include + +#include "driver/ledc.h" +#include "esp_clk_tree.h" +#include "esp_err.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" // IWYU pragma: keep +#include "freertos/task.h" +#include "hal/ledc_types.h" +#include "soc/clk_tree_defs.h" + +#include "buzzer.h" + +static const char* TAG = "BUZZER_C"; + +const uint32_t init_buzzer_freq = 2731; + +void buzzer_init(const uint32_t frequency) { + uint32_t clk_freq = 0; + ESP_ERROR_CHECK(esp_clk_tree_src_get_freq_hz( + SOC_MOD_CLK_RC_FAST, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &clk_freq)); + + uint32_t duty_resolution = + ledc_find_suitable_duty_resolution(clk_freq, frequency); + if (duty_resolution == 0) { + ESP_LOGE(TAG, "Could not determine optimal duty resolution.\n"); + return; + } + + ledc_timer_config_t ledc_config = {.speed_mode = LEDC_LOW_SPEED_MODE, + .timer_num = LEDC_TIMER_0, + .freq_hz = frequency, + .duty_resolution = duty_resolution, + .clk_cfg = LEDC_USE_RC_FAST_CLK}; + + ESP_ERROR_CHECK(ledc_timer_config(&ledc_config)); + + ledc_channel_config_t ledc_ch_config = { + .gpio_num = 9, + .speed_mode = LEDC_LOW_SPEED_MODE, + .channel = LEDC_CHANNEL_0, + .timer_sel = LEDC_TIMER_0, + .duty = (uint32_t)(pow(2, duty_resolution) / 2), + // .hpoint = ((uint32_t) pow(2, duty_resolution)) - 1, + .hpoint = 0, + .sleep_mode = LEDC_SLEEP_MODE_KEEP_ALIVE, + .flags.output_invert = false}; + + ESP_ERROR_CHECK(ledc_channel_config(&ledc_ch_config)); +} + +uint32_t modify_frequency(int amount) { + uint32_t freq = ledc_get_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0) + amount; + if (freq < 10) { + freq = 10; + } + buzzer_pause(); + ESP_ERROR_CHECK(ledc_set_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0, freq)); + buzzer_resume(); + return freq; +} + +uint32_t reset_frequency() { + ESP_ERROR_CHECK( + ledc_set_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0, init_buzzer_freq)); + return init_buzzer_freq; +} + +void set_frequency(const uint32_t freq) { + ESP_ERROR_CHECK(ledc_set_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0, freq)); +} + +void buzzer_pause() { + ESP_ERROR_CHECK(ledc_timer_pause(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0)); +} + +void buzzer_reset() { + ESP_ERROR_CHECK(ledc_timer_rst(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0)); +} + +void buzzer_resume() { + ESP_ERROR_CHECK(ledc_timer_resume(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0)); +} diff --git a/main/esp-pwm.c b/main/esp-pwm.c index cfbad5d..b1231b3 100644 --- a/main/esp-pwm.c +++ b/main/esp-pwm.c @@ -1,55 +1,34 @@ -#include -#include +#include -#include "driver/ledc.h" -#include "hal/ledc_types.h" -#include "soc/clk_tree_defs.h" -#include "esp_clk_tree.h" #include "esp_log.h" -#include "freertos/FreeRTOS.h" +#include "freertos/FreeRTOS.h" // IWYU pragma: keep +#include "freertos/projdefs.h" #include "freertos/task.h" -const char* TAG = "MAIN_CPP"; +#include "freq_slider.h" +#include "un.h" + +extern const uint32_t init_buzzer_freq; + +const char* TAG = "MAIN_C"; + void app_main() { - ESP_LOGI(TAG, "BOOT\n"); + ESP_LOGI(TAG, "BOOT"); - const uint32_t timer_freq = 2731; + // Only enable one task at a time. - uint32_t clk_freq = 0; - ESP_ERROR_CHECK(esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_RC_FAST, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &clk_freq)); + // if (xTaskCreate(freq_slider_task, "freq_slider_task", 4096, NULL, tskIDLE_PRIORITY, + // NULL) == pdFALSE) { + // ESP_LOGE(TAG, "Failed to create freq_slider_task."); + // } - uint32_t duty_resolution = ledc_find_suitable_duty_resolution(clk_freq, timer_freq); - if (duty_resolution == 0) { - ESP_LOGE(TAG, "Could not determine optimal duty resolution.\n"); - return; + if (xTaskCreate(un_task, "un_task", 4096, NULL, tskIDLE_PRIORITY, + NULL) == pdFALSE) { + ESP_LOGE(TAG, "Failed to create un_task."); } - ledc_timer_config_t ledc_config = { - .speed_mode = LEDC_LOW_SPEED_MODE, - .timer_num = LEDC_TIMER_0, - .freq_hz = timer_freq, - .duty_resolution = duty_resolution, - .clk_cfg = LEDC_USE_RC_FAST_CLK - }; - - ESP_ERROR_CHECK(ledc_timer_config(&ledc_config)); - - ledc_channel_config_t ledc_ch_config = { - .gpio_num = 9, - .speed_mode = LEDC_LOW_SPEED_MODE, - .channel = LEDC_CHANNEL_0, - .timer_sel = LEDC_TIMER_0, - .duty = (uint32_t) (pow(2, duty_resolution) / 2), - // .hpoint = ((uint32_t) pow(2, duty_resolution)) - 1, - .hpoint = 0, - .sleep_mode = LEDC_SLEEP_MODE_KEEP_ALIVE, - .flags.output_invert = false - }; - - ESP_ERROR_CHECK(ledc_channel_config(&ledc_ch_config)); - while (true) { - vTaskDelay(10000); + vTaskDelay(pdMS_TO_TICKS(10000)); } } diff --git a/main/freq_slider.c b/main/freq_slider.c new file mode 100644 index 0000000..0de6d6f --- /dev/null +++ b/main/freq_slider.c @@ -0,0 +1,40 @@ +#include + +#include "driver/usb_serial_jtag.h" +#include "portmacro.h" +#include "esp_log.h" + +#include "buzzer.h" +#include "arraylen.h" + +extern const uint32_t init_buzzer_freq; + +static const char* TAG = "FREQ_SLIDER_C"; + +void freq_slider_task(void* param) { + buzzer_init(init_buzzer_freq); + + usb_serial_jtag_driver_config_t jtag_config = {.rx_buffer_size = 1024, + .tx_buffer_size = 1024}; + ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&jtag_config)); + + int modify_amount = 10; + + char buf[4] = {0}; + while (true) { + int read_count = usb_serial_jtag_read_bytes(buf, ARRAY_LEN(buf) - 1, portMAX_DELAY); + buf[read_count + 1] = '\0'; + switch (buf[0]) { + case 'q': + ESP_LOGI(TAG, "Increasing frequency. New frequency: %d", modify_frequency(modify_amount)); + break; + case 'a': + ESP_LOGI(TAG, "Decreasing frequency. New frequency: %d", modify_frequency(-modify_amount)); + modify_frequency(-modify_amount); + break; + case '1': + reset_frequency(); + break; + } + } +} diff --git a/main/headers/arraylen.h b/main/headers/arraylen.h new file mode 100644 index 0000000..e90ec22 --- /dev/null +++ b/main/headers/arraylen.h @@ -0,0 +1,6 @@ +#ifndef ARRAY_LEN_H_ +#define ARRAY_LEN_H_ + +#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0])) + +#endif // ARRAY_LEN_H_ diff --git a/main/headers/buzzer.h b/main/headers/buzzer.h new file mode 100644 index 0000000..9713a49 --- /dev/null +++ b/main/headers/buzzer.h @@ -0,0 +1,14 @@ +#ifndef BUZZER_H_ +#define BUZZER_H_ + +#include + +void buzzer_init(const uint32_t frequency); +uint32_t modify_frequency(int amount); +uint32_t reset_frequency(); +void set_frequency(const uint32_t freq); +void buzzer_pause(); +void buzzer_reset(); +void buzzer_resume(); + +#endif // BUZZER_H_ diff --git a/main/headers/freq_slider.h b/main/headers/freq_slider.h new file mode 100644 index 0000000..48807b2 --- /dev/null +++ b/main/headers/freq_slider.h @@ -0,0 +1,6 @@ +#ifndef FREQ_SLIDER_H_ +#define FREQ_SLIDER_H_ + +void freq_slider_task(void* param); + +#endif // FREQ_SLIDER_H_ diff --git a/main/headers/un.h b/main/headers/un.h new file mode 100644 index 0000000..4b46221 --- /dev/null +++ b/main/headers/un.h @@ -0,0 +1,23 @@ +#ifndef UN_H_ +#define UN_H_ + +#include + +// https://mixbutton.com/music-tools/frequency-and-pitch/music-note-to-frequency-chart + +// Octave 2 +// typedef enum { P = -1, C = 65, D = 73, E = 82, F = 87, G = 98 } NoteFreq; + +// Octave 4 +typedef enum { P = -1, C = 262, D = 294, E = 330, F = 349, G = 392 } NoteFreq; + +typedef struct { + NoteFreq note; + uint32_t length; +} Note; + +const char* NoteFreqToStr(NoteFreq note); +void play_note(Note* note); +void un_task(void* param); + +#endif // UN_H_ diff --git a/main/un.c b/main/un.c new file mode 100644 index 0000000..88ec89b --- /dev/null +++ b/main/un.c @@ -0,0 +1,122 @@ +#include + +#include "esp_log.h" +#include "driver/usb_serial_jtag.h" +#include "freertos/FreeRTOS.h" // IWYU pragma: keep +#include "freertos/task.h" + +#include "un.h" +#include "buzzer.h" +#include "arraylen.h" + +extern const uint32_t init_buzzer_freq; + +static const char* TAG = "UN_C"; + +const char* NoteFreqToStr(NoteFreq note) { + switch (note) { + case C: + return "C"; + case D: + return "D"; + case E: + return "E"; + case F: + return "F"; + case G: + return "G"; + case P: + return "P"; + default: + return "INVALID NOTEFREQ"; + } +} + + +void play_note(Note* note) { + ESP_LOGI(TAG, "Playing note: %s %d", NoteFreqToStr(note->note), + note->length); + if (note->note != P) { + set_frequency(note->note); + buzzer_resume(); + } + vTaskDelay(pdMS_TO_TICKS(note->length)); + buzzer_pause(); +} + +void un_task(void* param) { + usb_serial_jtag_driver_config_t jtag_config = {.rx_buffer_size = 1024, + .tx_buffer_size = 1024}; + ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&jtag_config)); + + buzzer_init(init_buzzer_freq); + + const uint32_t quarter = 250; + const uint32_t half = 500; + const uint32_t whole = 1000; + + // clang-format off + Note sequence[] = { + {.note = C, .length = quarter}, + {.note = C, .length = quarter}, + {.note = C, .length = quarter}, + {.note = E, .length = quarter}, + + {.note = D, .length = quarter}, + {.note = D, .length = quarter}, + {.note = D, .length = quarter}, + {.note = F, .length = quarter}, + + {.note = E, .length = quarter}, + {.note = E, .length = quarter}, + {.note = D, .length = quarter}, + {.note = D, .length = quarter}, + + {.note = C, .length = half}, + {.note = P, .length = half}, + + {.note = E, .length = quarter}, + {.note = E, .length = quarter}, + {.note = E, .length = quarter}, + {.note = E, .length = quarter}, + + {.note = G, .length = half}, + {.note = F, .length = half}, + + {.note = D, .length = quarter}, + {.note = D, .length = quarter}, + {.note = D, .length = quarter}, + {.note = D, .length = quarter}, + + {.note = F, .length = half}, + {.note = E, .length = half}, + + {.note = C, .length = quarter}, + {.note = C, .length = quarter}, + {.note = C, .length = quarter}, + {.note = E, .length = quarter}, + + {.note = D, .length = quarter}, + {.note = D, .length = quarter}, + {.note = D, .length = quarter}, + {.note = F, .length = quarter}, + + {.note = E, .length = quarter}, + {.note = E, .length = quarter}, + {.note = D, .length = quarter}, + {.note = D, .length = quarter}, + + {.note = C, .length = whole}, + }; + // clang-format on + + char* buf[4] = {0}; + buzzer_pause(); + while (true) { + ESP_LOGI(TAG, "Press any button to play"); + usb_serial_jtag_read_bytes(buf, ARRAY_LEN(buf) - 1, portMAX_DELAY); + for (size_t i = 0; i < ARRAY_LEN(sequence); i++) { + play_note(&sequence[i]); + } + } +} diff --git a/sdkconfig b/sdkconfig index 76dbe42..8a5e051 100644 --- a/sdkconfig +++ b/sdkconfig @@ -501,7 +501,9 @@ CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y # CONFIG_BOOTLOADER_FACTORY_RESET is not set # CONFIG_BOOTLOADER_APP_TEST is not set CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y -# CONFIG_BOOTLOADER_WDT_ENABLE is not set +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 # CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set # CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set # CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set @@ -672,6 +674,7 @@ CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING=y # # CONFIG_APPTRACE_DEST_JTAG is not set CONFIG_APPTRACE_DEST_NONE=y +# CONFIG_APPTRACE_DEST_UART0 is not set # CONFIG_APPTRACE_DEST_UART1 is not set # CONFIG_APPTRACE_DEST_UART2 is not set CONFIG_APPTRACE_DEST_UART_NONE=y @@ -1278,17 +1281,14 @@ CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y # CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 -CONFIG_ESP_CONSOLE_UART_DEFAULT=y -# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set +# CONFIG_ESP_CONSOLE_UART_DEFAULT is not set +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y # CONFIG_ESP_CONSOLE_UART_CUSTOM is not set # CONFIG_ESP_CONSOLE_NONE is not set -# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set -CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_SECONDARY_NONE=y CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y -CONFIG_ESP_CONSOLE_UART=y -CONFIG_ESP_CONSOLE_UART_NUM=0 -CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0 -CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_CONSOLE_UART_NUM=-1 +CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=3 CONFIG_ESP_INT_WDT=y CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 CONFIG_ESP_TASK_WDT_EN=y @@ -2281,13 +2281,11 @@ CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 CONFIG_MAIN_TASK_STACK_SIZE=3584 -CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_DEFAULT is not set # CONFIG_CONSOLE_UART_CUSTOM is not set # CONFIG_CONSOLE_UART_NONE is not set # CONFIG_ESP_CONSOLE_UART_NONE is not set -CONFIG_CONSOLE_UART=y -CONFIG_CONSOLE_UART_NUM=0 -CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_CONSOLE_UART_NUM=-1 CONFIG_INT_WDT=y CONFIG_INT_WDT_TIMEOUT_MS=300 CONFIG_TASK_WDT=y