#include #include #include "driver/gpio.h" #include "driver/gptimer.h" #include "driver/ledc.h" #include "esp_attr.h" #include "esp_err.h" #include "esp_log.h" #include "esp_random.h" #include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include "freertos/task.h" #include "hal/gpio_types.h" #include "hal/ledc_types.h" #include "hal/timer_types.h" #include "soc/clk_tree_defs.h" /* Inputs */ // Clock In /* Controls */ #define GPIO_MUTATE_BTN (9) // Mutate Button In #define GPIO_TAP_TEMPO_BTN (10) // Tap Tempo Button In gptimer_handle_t tap_tempo_timer = NULL; static QueueHandle_t control_event_queue = NULL; /* Outputs */ #define GPIO_CLK_OUT (7) // Clock Out #define GPIO_GATE_OUT (8) // Gate CV Out gptimer_handle_t clk_cv_timer = NULL; gptimer_handle_t gate_cv_timer = NULL; /* LED GPIO Pins */ #define LEDC_CLK_OUT (5) #define LEDC_GATE_OUT (6) gptimer_handle_t clk_blink_timer = NULL; gptimer_handle_t gate_blink_timer = NULL; static const uint32_t DEFAULT_BPM = 120; static const uint8_t SEQ_MAX_LEN = 8; uint8_t sequence[SEQ_MAX_LEN] = {0}; uint8_t seq_len = SEQ_MAX_LEN; static const char *TAG = "sequencer"; uint32_t bpm_to_ms(uint32_t bpm) { return 60000 / bpm; } uint32_t ms_to_bpm(uint32_t ms) { return 60000 / ms; } static void randomize_seq(uint8_t *sequence) { for (uint8_t i = 0; i < SEQ_MAX_LEN; i++) { sequence[i] = esp_random() % 2; } } static void mutate_seq(uint8_t *sequence) { ESP_LOGI(TAG, "Mutating Sequence"); // pick a step to mutate uint8_t step = esp_random() % SEQ_MAX_LEN; if (sequence[step] == 1) { sequence[step] = 0; } else if (sequence[step] == 0) { sequence[step] = 1; } } static void IRAM_ATTR gpio_isr_handler(void* arg) { uint32_t gpio_num = (uint32_t)arg; xQueueSendFromISR(control_event_queue, &gpio_num, NULL); } static void control_event_handler(void* arg) { uint32_t gpio_num; while (1) { if(xQueueReceive(control_event_queue, &gpio_num, portMAX_DELAY)) { ESP_LOGI(TAG, "Handling control from GPIO %" PRIu32 , gpio_num); switch (gpio_num) { case GPIO_MUTATE_BTN: mutate_seq(sequence); break; } } } } static void controls_init(void) { // install gpio isr hservice gpio_install_isr_service(0); // Setup Mutate Button gpio_reset_pin(GPIO_MUTATE_BTN); gpio_set_direction(GPIO_MUTATE_BTN, GPIO_MODE_INPUT); gpio_set_intr_type(GPIO_MUTATE_BTN, GPIO_INTR_NEGEDGE); // Hook in handler for mutate button gpio_isr_handler_add(GPIO_MUTATE_BTN, gpio_isr_handler, (void*)GPIO_MUTATE_BTN); // Setup tap tempo Button gpio_reset_pin(GPIO_TAP_TEMPO_BTN); gpio_set_direction(GPIO_TAP_TEMPO_BTN, GPIO_MODE_INPUT); gpio_set_intr_type(GPIO_TAP_TEMPO_BTN, GPIO_INTR_NEGEDGE); // Hook in handler for tap tempo button gpio_isr_handler_add(GPIO_TAP_TEMPO_BTN, gpio_isr_handler, (void *)GPIO_TAP_TEMPO_BTN); // Setup tap tempo timer gptimer_config_t tap_tempo_timer_config = { .clk_src = GPTIMER_CLK_SRC_DEFAULT, .direction = GPTIMER_COUNT_UP, .resolution_hz = 1 * 1000 * 1000 // 1MHz; 1 tick = 1 µs }; ESP_ERROR_CHECK(gptimer_new_timer(&tap_tempo_timer_config, &tap_tempo_timer)); ESP_ERROR_CHECK(gptimer_enable(tap_tempo_timer)); } static void clk_cv_off_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) { gptimer_stop(clk_cv_timer); gpio_set_level(GPIO_CLK_OUT, 0); } static void gate_cv_off_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) { gptimer_stop(gate_cv_timer); gpio_set_level(GPIO_GATE_OUT, 0); } static void gpio_init(void) { // Setup gpio control event queue control_event_queue = xQueueCreate(10, sizeof(uint32_t)); // Setup Clock CV Output gpio_reset_pin(GPIO_CLK_OUT); gpio_set_direction(GPIO_CLK_OUT, GPIO_MODE_OUTPUT); // Setup Gate CV Output gpio_reset_pin(GPIO_GATE_OUT); gpio_set_direction(GPIO_GATE_OUT, GPIO_MODE_OUTPUT); // Setup CV output timer gptimer_config_t cv_out_timer_config = { .clk_src = GPTIMER_CLK_SRC_DEFAULT, .direction = GPTIMER_COUNT_UP, .resolution_hz = 1 * 1000 * 1000 // 1MHz; 1 tick = 1 µs }; ESP_ERROR_CHECK(gptimer_new_timer(&cv_out_timer_config, &clk_cv_timer)); ESP_ERROR_CHECK(gptimer_new_timer(&cv_out_timer_config, &gate_cv_timer)); // Configure timer alarm gptimer_alarm_config_t cv_off_alarm_config = { .alarm_count = 10 * 1000, // 10ms @ 1MHz .reload_count = 0, .flags.auto_reload_on_alarm = true }; ESP_ERROR_CHECK(gptimer_set_alarm_action(clk_cv_timer, &cv_off_alarm_config)); ESP_ERROR_CHECK(gptimer_set_alarm_action(gate_cv_timer, &cv_off_alarm_config)); //register clk callback gptimer_event_callbacks_t clk_cbs = {.on_alarm = clk_cv_off_alarm_cb}; ESP_ERROR_CHECK(gptimer_register_event_callbacks(clk_cv_timer, &clk_cbs, NULL)); ESP_ERROR_CHECK(gptimer_enable(clk_cv_timer)); // register gate callback gptimer_event_callbacks_t gate_cbs = {.on_alarm = gate_cv_off_alarm_cb}; ESP_ERROR_CHECK(gptimer_register_event_callbacks(gate_cv_timer, &gate_cbs, NULL)); ESP_ERROR_CHECK(gptimer_enable(gate_cv_timer)); } static void gate_led_off_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) { gptimer_stop(gate_blink_timer); ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0)); ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1)); } static void clk_led_off_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) { gptimer_stop(clk_blink_timer); ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0)); ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0)); } static void ledc_init(void) { // Setup LEDC PWM timer configuration ledc_timer_config_t ledc_timer = { .speed_mode = LEDC_LOW_SPEED_MODE, .timer_num = LEDC_TIMER_0, .duty_resolution = LEDC_TIMER_13_BIT, .freq_hz = 5000, .clk_cfg = LEDC_AUTO_CLK }; ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); // Setup Clock LED ledc_channel_config_t ledc_clk_channel = { .channel = LEDC_CHANNEL_0, .gpio_num = LEDC_CLK_OUT, .speed_mode = LEDC_LOW_SPEED_MODE, .timer_sel = LEDC_TIMER_0, .intr_type = LEDC_INTR_DISABLE, .duty = 0, .hpoint = 0 }; ESP_ERROR_CHECK(ledc_channel_config(&ledc_clk_channel)); // Setup Gate LED ledc_channel_config_t ledc_gate_channel = { .channel = LEDC_CHANNEL_1, .gpio_num = LEDC_GATE_OUT, .speed_mode = LEDC_LOW_SPEED_MODE, .timer_sel = LEDC_TIMER_0, .intr_type = LEDC_INTR_DISABLE, .duty = 0, .hpoint = 0 }; ESP_ERROR_CHECK(ledc_channel_config(&ledc_gate_channel)); // Setup LED blink timer gptimer_config_t led_blink_timer_config = { .clk_src = GPTIMER_CLK_SRC_DEFAULT, .direction = GPTIMER_COUNT_UP, .resolution_hz = 1 * 1000 * 1000 // 1MHz; 1 tick = 1 µs }; ESP_ERROR_CHECK(gptimer_new_timer(&led_blink_timer_config, &clk_blink_timer)); ESP_ERROR_CHECK(gptimer_new_timer(&led_blink_timer_config, &gate_blink_timer)); // Configure timer alarm gptimer_alarm_config_t led_off_alarm_config = { .alarm_count = 50 * 1000, // 50ms @ 1MHz .reload_count = 0, .flags.auto_reload_on_alarm = true }; ESP_ERROR_CHECK(gptimer_set_alarm_action(clk_blink_timer, &led_off_alarm_config)); ESP_ERROR_CHECK(gptimer_set_alarm_action(gate_blink_timer, &led_off_alarm_config)); //register clk callback gptimer_event_callbacks_t clk_cbs = {.on_alarm = clk_led_off_alarm_cb}; ESP_ERROR_CHECK(gptimer_register_event_callbacks(clk_blink_timer, &clk_cbs, NULL)); ESP_ERROR_CHECK(gptimer_enable(clk_blink_timer)); // register gate callback gptimer_event_callbacks_t gate_cbs = {.on_alarm = gate_led_off_alarm_cb}; ESP_ERROR_CHECK(gptimer_register_event_callbacks(gate_blink_timer, &gate_cbs, NULL)); ESP_ERROR_CHECK(gptimer_enable(gate_blink_timer)); } static void blink_led(ledc_channel_t channel) { ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, channel, 4095)); ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, channel)); switch (channel) { case (LEDC_CHANNEL_0): ESP_ERROR_CHECK(gptimer_start(clk_blink_timer)); break; case (LEDC_CHANNEL_1): ESP_ERROR_CHECK(gptimer_start(gate_blink_timer)); break; default: break; } } static void pulse_cv(uint8_t gpio_num) { gpio_set_level(gpio_num, 1); switch (gpio_num) { case (GPIO_CLK_OUT): ESP_ERROR_CHECK(gptimer_start(clk_cv_timer)); break; case (GPIO_GATE_OUT): ESP_ERROR_CHECK(gptimer_start(gate_cv_timer)); break; } } void app_main(void) { /* Initialize Peripherals */ /* Initialize GPIO */ gpio_init(); controls_init(); // Start task to handle control events xTaskCreate(control_event_handler, "control event handler", 2048, NULL, 10, NULL); /* Initialize Monitor LEDs */ ledc_init(); /* Initialize sequence */ randomize_seq(sequence); /* Main Loop */ while (1) { for (uint8_t step = 0; step < seq_len; step++) { blink_led(LEDC_CHANNEL_0); // blink clock led pulse_cv(GPIO_CLK_OUT); // if step has been set for sequence if (sequence[step] == 1) { pulse_cv(GPIO_GATE_OUT); blink_led(LEDC_CHANNEL_1); // blink gate triggered led } printf("%i", sequence[step]); vTaskDelay(bpm_to_ms(DEFAULT_BPM)/ portTICK_PERIOD_MS); } printf("\n"); } }