204 lines
6.2 KiB
C
204 lines
6.2 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/queue.h"
|
|
#include "driver/gpio.h"
|
|
#include "driver/adc.h"
|
|
#include "driver/pcnt.h"
|
|
#include "esp_log.h"
|
|
|
|
#include "H2201_buttons.h"
|
|
#include "H2201_i2c.h"
|
|
|
|
static const char *TAG = "H2201_buttons";
|
|
|
|
static QueueHandle_t H2201_button_event_queue = NULL;
|
|
static QueueHandle_t H2201_encoder_volume_queue = NULL;
|
|
|
|
static uint32_t encoder_pcnt_unit = 0;
|
|
|
|
static void IRAM_ATTR gpio_isr_handler(void *arg)
|
|
{
|
|
uint32_t gpio_num = (uint32_t)arg;
|
|
xQueueSendFromISR(H2201_button_event_queue, &gpio_num, NULL);
|
|
}
|
|
|
|
static void H2201_button_task(void *arg)
|
|
{
|
|
uint32_t io_num;
|
|
uint32_t encoder_val;
|
|
for (;;)
|
|
{
|
|
if (xQueueReceive(H2201_button_event_queue, &io_num, 10 / portTICK_PERIOD_MS))
|
|
{
|
|
int level = gpio_get_level(io_num);
|
|
// printf("GPIO[%d] intr, val: %d\n", io_num, level);
|
|
if (level == 0)
|
|
{
|
|
H2201_i2c_beep();
|
|
}
|
|
}
|
|
if (xQueueReceive(H2201_encoder_volume_queue, &encoder_val, 10 / portTICK_PERIOD_MS))
|
|
{
|
|
// printf("Encoder value: %zu\n", encoder_val);
|
|
if (encoder_val == 1)
|
|
{
|
|
H2201_i2c_mastervolume_up();
|
|
}
|
|
else
|
|
{
|
|
H2201_i2c_mastervolume_down();
|
|
}
|
|
}
|
|
|
|
// printf("1=%d ", H2201_dipswitch_read(1));
|
|
// printf("2=%d ", H2201_dipswitch_read(2));
|
|
// printf("3=%d ", H2201_dipswitch_read(3));
|
|
// printf("4=%d ", H2201_dipswitch_read(4));
|
|
// printf("5=%d ", H2201_dipswitch_read(5));
|
|
// printf("6=%d ", H2201_dipswitch_read(6));
|
|
// printf("7=%d ", H2201_dipswitch_read(7));
|
|
// printf("8=%d\n", H2201_dipswitch_read(8));
|
|
}
|
|
}
|
|
//******************* shiftregsiter ********************************
|
|
void H2201_shiftregister_init(void)
|
|
{
|
|
gpio_set_direction(SHIFT_CLOCK, GPIO_MODE_OUTPUT);
|
|
gpio_set_direction(SHIFT_LATCH, GPIO_MODE_OUTPUT);
|
|
gpio_set_direction(SHIFT_DATA, GPIO_MODE_INPUT);
|
|
}
|
|
|
|
void H2201_shiftregister_read(bool dipswitch[9])
|
|
{
|
|
// clock inputs in registers
|
|
gpio_set_level(SHIFT_LATCH, 1);
|
|
gpio_set_level(SHIFT_CLOCK, 1);
|
|
gpio_set_level(SHIFT_CLOCK, 0);
|
|
gpio_set_level(SHIFT_LATCH, 0);
|
|
|
|
// get de bits
|
|
for (size_t i = 8; i > 0; --i)
|
|
{
|
|
gpio_set_level(SHIFT_CLOCK, 1);
|
|
dipswitch[i] = gpio_get_level(SHIFT_DATA);
|
|
gpio_set_level(SHIFT_CLOCK, 0);
|
|
}
|
|
}
|
|
|
|
bool H2201_dipswitch_read(int sw)
|
|
{
|
|
if (sw < 0 || sw > 8)
|
|
{
|
|
return false;
|
|
}
|
|
bool dipswitch[9];
|
|
H2201_shiftregister_read(dipswitch);
|
|
return dipswitch[sw];
|
|
}
|
|
|
|
//******************* buttons ********************************
|
|
void H2201_buttons_init(void)
|
|
{
|
|
gpio_config_t io_conf = {};
|
|
|
|
io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
|
io_conf.pin_bit_mask = ((1ULL << BUTTON_1) | (1ULL << BUTTON_2) | (1ULL << BUTTON_3) | (1ULL << BUTTON_4));
|
|
|
|
io_conf.mode = GPIO_MODE_INPUT;
|
|
gpio_config(&io_conf);
|
|
|
|
// Please do not use the interrupt of GPIO36 and GPIO39 when using ADC or Wi-Fi with sleep mode enabled.
|
|
// Please refer to the comments of `adc1_get_raw`.
|
|
// Please refer to section 3.11 of 'ECO_and_Workarounds_for_Bugs_in_ESP32' for the description of this issue.
|
|
// As a workaround, call adc_power_acquire() in the app. This will result in higher power consumption (by ~1mA),
|
|
// but will remove the glitches on GPIO36 and GPIO39.
|
|
adc_power_acquire();
|
|
|
|
H2201_button_event_queue = xQueueCreate(20, sizeof(uint32_t));
|
|
xTaskCreate(H2201_button_task, "H2201_button_task", 4096, NULL, 10, NULL);
|
|
|
|
gpio_install_isr_service(ESP_INTR_FLAG_EDGE);
|
|
gpio_isr_handler_add(BUTTON_1, gpio_isr_handler, (void *)BUTTON_1);
|
|
gpio_isr_handler_add(BUTTON_2, gpio_isr_handler, (void *)BUTTON_2);
|
|
gpio_isr_handler_add(BUTTON_3, gpio_isr_handler, (void *)BUTTON_3);
|
|
gpio_isr_handler_add(BUTTON_4, gpio_isr_handler, (void *)BUTTON_4);
|
|
}
|
|
//******************* encoder ********************************
|
|
|
|
static void IRAM_ATTR H2201_encoder_pcnt_overflow_handler(void *arg)
|
|
{
|
|
uint32_t status;
|
|
pcnt_get_event_status(encoder_pcnt_unit, &status);
|
|
if (status & PCNT_EVT_H_LIM)
|
|
{
|
|
uint32_t val = 1;
|
|
xQueueSendFromISR(H2201_encoder_volume_queue, &val, NULL);
|
|
}
|
|
else if (status & PCNT_EVT_L_LIM)
|
|
{
|
|
uint32_t val = 0;
|
|
xQueueSendFromISR(H2201_encoder_volume_queue, &val, NULL);
|
|
}
|
|
}
|
|
|
|
void H2201_encoder_init(void)
|
|
{
|
|
H2201_encoder_volume_queue = xQueueCreate(10, sizeof(uint32_t));
|
|
|
|
// Configure channel 0
|
|
pcnt_config_t dev_config = {
|
|
.pulse_gpio_num = ROTARY_A_GPIO,
|
|
.ctrl_gpio_num = ROTARY_B_GPIO,
|
|
.channel = PCNT_CHANNEL_0,
|
|
.unit = encoder_pcnt_unit,
|
|
.pos_mode = PCNT_COUNT_DEC,
|
|
.neg_mode = PCNT_COUNT_INC,
|
|
.lctrl_mode = PCNT_MODE_REVERSE,
|
|
.hctrl_mode = PCNT_MODE_KEEP,
|
|
// .counter_h_lim = ROTARY_HIGH_LIMIT,
|
|
// .counter_l_lim = ROTARY_LOW_LIMIT,
|
|
.counter_h_lim = (1),
|
|
.counter_l_lim = (-1),
|
|
};
|
|
if (pcnt_unit_config(&dev_config) != ESP_OK)
|
|
{
|
|
ESP_LOGE(TAG, "config pcnt channel 0 failed");
|
|
}
|
|
|
|
// register interrupt handler
|
|
if (pcnt_isr_service_install(0) != ESP_OK)
|
|
{
|
|
ESP_LOGE(TAG, "install isr service failed");
|
|
}
|
|
pcnt_isr_handler_add(dev_config.unit, H2201_encoder_pcnt_overflow_handler, &dev_config.unit);
|
|
// pcnt_event_enable(dev_config.unit, PCNT_EVT_ZERO);
|
|
pcnt_event_enable(dev_config.unit, PCNT_EVT_H_LIM);
|
|
pcnt_event_enable(dev_config.unit, PCNT_EVT_L_LIM);
|
|
|
|
/* Configure and enable the input filter */
|
|
if (pcnt_set_filter_value(dev_config.unit, ROTARY_GLITCH_US * 80) != ESP_OK)
|
|
{
|
|
ESP_LOGE(TAG, "set glitch filter failed");
|
|
}
|
|
if (ROTARY_GLITCH_US)
|
|
{
|
|
pcnt_filter_enable(dev_config.unit);
|
|
}
|
|
else
|
|
{
|
|
pcnt_filter_disable(dev_config.unit);
|
|
}
|
|
|
|
// PCNT pause and reset value
|
|
pcnt_counter_pause(dev_config.unit);
|
|
pcnt_counter_clear(dev_config.unit);
|
|
|
|
// start encoder
|
|
if (pcnt_counter_resume(dev_config.unit) != ESP_OK)
|
|
{
|
|
ESP_LOGE(TAG, "counter start failed");
|
|
}
|
|
} |