OK here's where I am.
I'm using the AiThinker A1S WiFi/BT/Audio board.
The schematic is here:
http://wiki.ai-thinker.com/_media/esp32 ... custom.pdf
There are 6 buttons which route to IO5, IO13, IO18, IO19, IO23, IO36. They are pulled up via an R/2R ladder which eventually goes to IO36, but it also appears that each button can be used for an individual on/off input.
Then I'm using the craftmetrics code from here:
https://github.com/craftmetrics/esp32-button
And I've written a C++ "main" file because eventually I'm trying to merge this in with a C++ based project.
main.cpp:
Code: Select all
/* button press Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_spi_flash.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
extern "C" {
#include "button.h"
}
extern "C" {
void app_main(void);
QueueHandle_t * button_init(unsigned long long );
}
void app_main(void)
{
button_event_t ev;
QueueHandle_t button_events = button_init(PIN_BIT(5) | PIN_BIT(13) | PIN_BIT(18) | PIN_BIT(19) | PIN_BIT(23));
while (true) {
if (xQueueReceive(button_events, &ev, 1000/portTICK_PERIOD_MS)) {
if ((ev.pin == 1) && (ev.event == BUTTON_DOWN)) {
ESP_LOGI("Button 1", "Down");
}
if ((ev.pin == 2) && (ev.event == BUTTON_DOWN)) {
ESP_LOGI("Button 2", "Down");
}
}
}
}
button.c:
Code: Select all
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "button.h"
#define TAG "BUTTON"
typedef struct {
uint8_t pin;
bool inverted;
uint16_t history;
uint64_t down_time;
} debounce_t;
int pin_count = -1;
debounce_t * debounce;
QueueHandle_t * queue;
static void update_button(debounce_t *d) {
d->history = (d->history << 1) | gpio_get_level(d->pin);
}
#define MASK 0b1111000000111111
static bool button_rose(debounce_t *d) {
if ((d->history & MASK) == 0b0000000000111111) {
d->history = 0xffff;
return 1;
}
return 0;
}
static bool button_fell(debounce_t *d) {
if ((d->history & MASK) == 0b1111000000000000) {
d->history = 0x0000;
return 1;
}
return 0;
}
static bool button_down(debounce_t *d) {
if (d->inverted) return button_fell(d);
return button_rose(d);
}
static bool button_up(debounce_t *d) {
if (d->inverted) return button_rose(d);
return button_fell(d);
}
#define LONG_PRESS_DURATION (2000)
static uint32_t millis() {
return esp_timer_get_time() / 1000;
}
static void send_event(debounce_t db, int ev) {
button_event_t event = {
.pin = db.pin,
.event = ev,
};
xQueueSend(queue, &event, portMAX_DELAY);
}
static void button_task(void *pvParameter)
{
while (1) {
for (int idx=0; idx<pin_count; idx++) {
update_button(&debounce[idx]);
if (debounce[idx].down_time && (millis() - debounce[idx].down_time > LONG_PRESS_DURATION)) {
debounce[idx].down_time = 0;
ESP_LOGI(TAG, "%d LONG", debounce[idx].pin);
int i=0;
while (!button_up(&debounce[idx])) {
if (!i) send_event(debounce[idx], BUTTON_DOWN);
i++;
if (i>=5) i=0;
vTaskDelay(10/portTICK_PERIOD_MS);
update_button(&debounce[idx]);
}
ESP_LOGI(TAG, "%d UP", debounce[idx].pin);
send_event(debounce[idx], BUTTON_UP);
} else if (button_down(&debounce[idx])) {
debounce[idx].down_time = millis();
ESP_LOGI(TAG, "%d DOWN", debounce[idx].pin);
send_event(debounce[idx], BUTTON_DOWN);
} else if (button_up(&debounce[idx])) {
debounce[idx].down_time = 0;
ESP_LOGI(TAG, "%d UP", debounce[idx].pin);
send_event(debounce[idx], BUTTON_UP);
}
}
vTaskDelay(10/portTICK_PERIOD_MS);
}
}
QueueHandle_t * button_init(unsigned long long pin_select) {
if (pin_count != -1) {
ESP_LOGI(TAG, "Already initialized");
return NULL;
}
// Configure the pins
gpio_config_t io_conf;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = pin_select;
gpio_config(&io_conf);
// Scan the pin map to determine number of pins
pin_count = 0;
for (int pin=0; pin<=39; pin++) {
if ((1ULL<<pin) & pin_select) {
pin_count++;
}
}
// Initialize global state and queue
debounce = calloc(pin_count, sizeof(debounce_t));
queue = xQueueCreate(4, sizeof(button_event_t));
// Scan the pin map to determine each pin number, populate the state
uint32_t idx = 0;
for (int pin=0; pin<=39; pin++) {
if ((1ULL<<pin) & pin_select) {
ESP_LOGI(TAG, "Registering button input: %d", pin);
debounce[idx].pin = pin;
debounce[idx].down_time = 0;
debounce[idx].inverted = true;
if (debounce[idx].inverted) debounce[idx].history = 0xffff;
idx++;
}
}
// Spawn a task to monitor the pins
xTaskCreate(&button_task, "button_task", 4096, NULL, 10, NULL);
return queue;
}
button.h:
Code: Select all
#define PIN_BIT(x) (1ULL<<x)
#define BUTTON_DOWN (1)
#define BUTTON_UP (2)
typedef struct {
uint8_t pin;
uint8_t event;
} button_event_t;
QueueHandle_t * button_init(unsigned long long );
Then, when I build, upload, and run the program, I get this output:
Code: Select all
I (0) cpu_start: App cpu up.
I (1151) spiram: SPI SRAM memory test OK
I (1151) heap_init: Initializing. RAM available for dynamic allocation:
I (1151) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (1157) heap_init: At 3FFB3038 len 0002CFC8 (179 KiB): DRAM
I (1164) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (1170) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (1177) heap_init: At 4008C0A0 len 00013F60 (79 KiB): IRAM
I (1183) cpu_start: Pro cpu start user code
I (1201) spi_flash: detected chip: generic
I (1202) spi_flash: flash io: dio
I (1211) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (1212) gpio: GPIO[5]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1222) gpio: GPIO[13]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1222) gpio: GPIO[18]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1232) gpio: GPIO[19]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1242) gpio: GPIO[23]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1252) BUTTON: Registering button input: 5
I (1262) BUTTON: Registering button input: 13
I (1262) BUTTON: Registering button input: 18
I (1272) BUTTON: Registering button input: 19
I (1272) BUTTON: Registering button input: 23
I (1332) BUTTON: 13 DOWN
I (1332) BUTTON: 18 DOWN
I (1332) BUTTON: 23 DOWN
I (3342) BUTTON: 13 LONG
Keep in mind that I am not holding any of the buttons down. Also, when I press the buttons, I don't get any additional output on the console.
The example wasn't written specifically for the ESP32-A1s board, but GPIO numbers should be accurate. I went off to the AI-Thinker website, which I was able to partially translate to English using the Chrome browser, and looked as hard I could for any ESP32-A1S specific example/demo code. Unfortunately all links just go back to Espressif application notes for the Lyra boards. Seems like AIThinker didn't bother to put together any specific code examples for their own boards, oddly enough. However, I'm skeptical that has anything to do with it.
Ideas? Suggestions?
Thanks,
DL