diff --git a/configure.ac b/configure.ac
index 6b7774e..81c3c3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,6 +31,7 @@ AC_CONFIG_FILES([
modules/Makefile
examples/Makefile
examples/0blink/Makefile
+ examples/0button/Makefile
examples/0hello/Makefile
examples/0ledctrl/Makefile
examples/1rmtblink/Makefile
diff --git a/examples/0button/Makefile.am b/examples/0button/Makefile.am
new file mode 100644
index 0000000..cacaaf1
--- /dev/null
+++ b/examples/0button/Makefile.am
@@ -0,0 +1,20 @@
+include $(top_srcdir)/scripts/elf2bin.mk
+include $(top_srcdir)/ld/flags.mk
+
+noinst_HEADERS = defines.h
+
+AM_CFLAGS = -std=c11 -flto
+AM_CPPFLAGS = -I$(top_srcdir)/src -I$(srcdir)
+AM_LDFLAGS += -T $(top_srcdir)/ld/esp32.rom.ld \
+ -T $(top_srcdir)/ld/esp32.rom.redefined.ld
+LDADD = $(top_builddir)/src/libesp32basic.a
+
+bin_PROGRAMS = \
+ buttonisr.elf
+
+if WITH_BINARIES
+CLEANFILES = \
+ buttonisr.bin
+endif
+
+BUILT_SOURCES = $(CLEANFILES)
diff --git a/examples/0button/README.md b/examples/0button/README.md
new file mode 100644
index 0000000..fa38d1a
--- /dev/null
+++ b/examples/0button/README.md
@@ -0,0 +1,13 @@
+### Listening on button press event
+
+This example demonstrates how to set up an ISR on GPIO event.
+
+#### Hardware components
+
+B0: BOOT button
+
+#### Connections
+
+```
+ESP32.GPIO0 -- B0 (builtin) -- ESP32.GND
+```
diff --git a/examples/0button/buttonisr.c b/examples/0button/buttonisr.c
new file mode 100644
index 0000000..2aabbc9
--- /dev/null
+++ b/examples/0button/buttonisr.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2024 SZIGETI János
+ *
+ * This file is part of Bilis ESP32 Basic, which is released under GNU General Public License.version 3.
+ * See LICENSE or for full license details.
+ */
+#include
+#include
+#include
+#include
+#include
+
+#include "esp_attr.h"
+#include "dport.h"
+#include "gpio.h"
+#include "iomux.h"
+#include "main.h"
+#include "defines.h"
+#include "romfunctions.h"
+#include "typeaux.h"
+#include "uart.h"
+#include "utils/uartutils.h"
+
+// =================== Hard constants =================
+
+#define BUTTON_GPIO 0U
+#define INT_CH 22U
+
+// ============= Local types ===============
+
+// ================ Local function declarations =================
+static void _button_init();
+static void _button_cycle(uint64_t u64Ticks);
+
+// =================== Global constants ================
+const bool gbStartAppCpu = START_APP_CPU;
+const uint16_t gu16Tim00Divisor = TIM0_0_DIVISOR;
+const uint64_t gu64tckSchedulePeriod = (CLK_FREQ_HZ / SCHEDULE_FREQ_HZ);
+
+// ==================== Local Data ================
+static volatile bool gbLedOn = false;
+static const char acMessage[] = "Button pressed.\n";
+
+// Implementation
+
+IRAM_ATTR static void _button_isr(void *pvParam) {
+ bool bButtonEvent = gsGPIO.STATUS & (1 << BUTTON_GPIO);
+ if (bButtonEvent) {
+ gsGPIO.STATUS_W1TC = (1 << BUTTON_GPIO);
+ bool bLevel = gsGPIO.IN & (1 << BUTTON_GPIO);
+ if (!bLevel) {
+ for (int i = 0; i < ARRAY_SIZE(acMessage) - 1; ++i) {
+ gsUART0.FIFO = acMessage[i];
+ }
+ }
+ }
+}
+
+static void _button_init() {
+ IomuxGpioConfReg rIOMux;
+ rIOMux.raw = iomux_get_gpioconf(BUTTON_GPIO);
+ rIOMux.u1FunIE = 1;
+ iomux_set_gpioconf(BUTTON_GPIO, rIOMux);
+ SGpioPinReg sPinReg = {
+ .u3PinIntType = 3,
+ .u5PinIntEn = 5
+ };
+ gsGPIO.PIN[BUTTON_GPIO] = sPinReg;
+
+ // register ISR and enable it
+ ECpu eCpu = CPU_PRO;
+ RegAddr prDportIntMap = (eCpu == CPU_PRO ? &dport_regs()->PRO_GPIO_INTERRUPT_MAP : &dport_regs()->APP_GPIO_INTERRUPT_MAP);
+
+ *prDportIntMap = INT_CH;
+ _xtos_set_interrupt_handler_arg(INT_CH, _button_isr, 0);
+ ets_isr_unmask(1 << INT_CH);
+
+}
+
+static void _button_cycle(uint64_t u64Ticks) {
+ static uint64_t u64tckNext = 0;
+
+ if (u64tckNext < u64Ticks) {
+ bool bLevel = gsGPIO.IN & (1 << BUTTON_GPIO);
+ gsUART0.FIFO = bLevel ? '^' : '_';
+ u64tckNext += MS2TICKS(2000);
+ }
+}
+
+// ====================== Interface functions =========================
+
+void prog_init_pro_pre() {
+ gsUART0.CLKDIV = APB_FREQ_HZ / 115200;
+ _button_init();
+}
+
+void prog_init_app() {
+}
+
+void prog_init_pro_post() {
+}
+
+void prog_cycle_app(uint64_t u64tckNow) {
+}
+
+void prog_cycle_pro(uint64_t u64tckNow) {
+ _button_cycle(u64tckNow);
+}
diff --git a/examples/0button/defines.h b/examples/0button/defines.h
new file mode 100644
index 0000000..d61d4d7
--- /dev/null
+++ b/examples/0button/defines.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2024 SZIGETI János
+ *
+ * This file is part of Bilis ESP32 Basic, which is released under GNU General Public License.version 3.
+ * See LICENSE or for full license details.
+ */
+#ifndef DEFINES_H
+#define DEFINES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // TIMINGS
+ // const -- do not change this value
+#define APB_FREQ_HZ 80000000U // 80 MHz
+
+ // variables
+#define TIM0_0_DIVISOR 2U
+#define START_APP_CPU 0U
+#define SCHEDULE_FREQ_HZ 1000U // 10KHz
+
+ // derived invariants
+#define CLK_FREQ_HZ (APB_FREQ_HZ / TIM0_0_DIVISOR) // 40 MHz
+#define TICKS_PER_MS (CLK_FREQ_HZ / 1000U) // 40000
+#define TICKS_PER_US (CLK_FREQ_HZ / 1000000U) // 40
+
+#define MS2TICKS(X) ((X) * TICKS_PER_MS)
+#define HZ2APBTICKS(X) (APB_FREQ_HZ / (X))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DEFINES_H */
+
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 87db8b2..7c3e446 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -1,2 +1,2 @@
AUTOMAKE_OPTIONS =
-SUBDIRS=0blink 0hello 0ledctrl 1rmtblink 1rmtmorse 1rmtmusic 3prog1 1rmtws2812
+SUBDIRS=0blink 0button 0hello 0ledctrl 1rmtblink 1rmtmorse 1rmtmusic 3prog1 1rmtws2812
diff --git a/src/gpio.h b/src/gpio.h
index 62b433d..9aa35fc 100644
--- a/src/gpio.h
+++ b/src/gpio.h
@@ -15,6 +15,20 @@ extern "C" {
// Based on:
// https://github.com/espressif/esp-idf/blob/6b3da6b1882f3b72e904cc90be67e9c4e3f369a9/components/soc/esp32/include/soc/gpio_reg.h
+ typedef volatile union {
+
+ volatile struct {
+ uint32_t rsvd0 : 2;
+ uint32_t u1PinPadDriver : 1;
+ uint32_t rsvd4 : 4;
+ uint32_t u3PinIntType : 3;
+ uint32_t bWakeUpEn : 1;
+ uint32_t rsvd11 : 2;
+ uint32_t u5PinIntEn : 5;
+ uint32_t rsvd18 : 14;
+ };
+ volatile uint32_t raw;
+ } SGpioPinReg;
typedef struct {
Reg BT_SELECT;
@@ -51,7 +65,7 @@ extern "C" {
Reg PCPU_INT1;
Reg PCPU_NMI_INT1;
Reg CPUSDIO_INT1;
- Reg PIN[40];
+ SGpioPinReg PIN[40];
Reg cali_conf;
Reg cali_data;
Reg FUNC_IN_SEL_CFG[256];
diff --git a/src/iomux.h b/src/iomux.h
index d317ade..e66dd74 100644
--- a/src/iomux.h
+++ b/src/iomux.h
@@ -54,6 +54,9 @@ extern "C" {
static inline void iomux_set_gpioconf(uint8_t u8GpioNum, IomuxGpioConfReg rGpioConf) {
register_set(&grIOMUX + gau8IomuxGpioIdx[u8GpioNum], rGpioConf.raw);
}
+ static inline Reg iomux_get_gpioconf(uint8_t u8GpioNum) {
+ return register_read(&grIOMUX + gau8IomuxGpioIdx[u8GpioNum]);
+ }
#ifdef __cplusplus
}