Bare metal programming
Posted: Wed Jul 30, 2025 6:55 pm
Can somebody guide me in Interruption programming. I've worked with the ESP-IDF but now I'm diving in Bare Metal Programming, so I would like to set up interruptions for GPIO but, tried everything and still not working. What do I have to do?
Code: Select all
#include <stdint.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "esp_rom_sys.h" // For esp_rom_printf
// IO MUX Registers
#define IO_MUX_MTMS_REG *((volatile uint32_t*)0x3FF49030) // GPIO14
#define IO_MUX_GPIO2_REG *((volatile uint32_t*)0x3FF49040) // GPIO2
#define IO_MUX_GPIO18_REG *((volatile uint32_t*)0x3FF49070) // GPIO18
// GPIO Configuration Registers
#define GPIO_FUNC_OUT_SEL_CFG_REG(n) (*((volatile uint32_t*)(0x3FF44530 + (0x4 * (n)))))
#define GPIO_PIN_REG(n) (*((volatile uint32_t*)(0x3FF44088 + (0x4 * (n)))))
// GPIO Enable Registers (Atomic)
#define GPIO_ENABLE_W1TS_REG *((volatile uint32_t*)0x3FF44024) // Write 1 to set
#define GPIO_ENABLE_W1TC_REG *((volatile uint32_t*)0x3FF44028) // Write 1 to clear
// GPIO Output Registers (Atomic)
#define GPIO_OUT_W1TS_REG *((volatile uint32_t*)0x3FF44008) // Write 1 to set
#define GPIO_OUT_W1TC_REG *((volatile uint32_t*)0x3FF4400C) // Write 1 to clear
// GPIO Input & Interrupt Status Registers
#define GPIO_IN_REG *((volatile uint32_t*)0x3FF4403C)
#define GPIO_STATUS_W1TC_REG *((volatile uint32_t*)0x3FF4404C) // Write 1 to clear
#define READ_INPUT(n) ((GPIO_IN_REG >> (n)) & 0x1)
static void IRAM_ATTR gpio_isr_handler(void *arg) {
// WARNING: esp_rom_printf is not fully ISR-safe. For debugging only.
esp_rom_printf("ISR Fired!\n");
// It's good practice to clear the interrupt status first
GPIO_STATUS_W1TC_REG = (1 << 18);
// Toggle GPIO2
static uint8_t level = 0;
level ^= 1;
if (level) {
GPIO_OUT_W1TS_REG = (1 << 2);
} else {
GPIO_OUT_W1TC_REG = (1 << 2);
}
}
void config_gpio() {
// --- Configure GPIO14 as Output (for blinking) ---
IO_MUX_MTMS_REG = (IO_MUX_MTMS_REG & ~(0b1111 << 12)) | (0b010 << 12);
GPIO_FUNC_OUT_SEL_CFG_REG(14) = 0x100;
GPIO_ENABLE_W1TS_REG = (1 << 14);
// --- Configure GPIO2 as Output (for ISR) ---
IO_MUX_GPIO2_REG = (IO_MUX_GPIO2_REG & ~(0b1111 << 12)) | (0b010 << 12);
GPIO_FUNC_OUT_SEL_CFG_REG(2) = 0x100;
GPIO_ENABLE_W1TS_REG = (1 << 2);
// --- Configure GPIO18 as Input with Interrupt ---
GPIO_ENABLE_W1TC_REG = (1 << 18); // Set as input
IO_MUX_GPIO18_REG |= (1 << 9) | (1 << 8); // Input Enable + Pull-Up
IO_MUX_GPIO18_REG &= ~(1 << 7); // Disable Pull-Down
// Atomically configure interrupt for falling edge (type 2) and enable for PRO CPU (ena bit 0)
uint32_t pin_reg_val = GPIO_PIN_REG(18);
pin_reg_val &= ~((0x7 << 7) | (0x1F << 13)); // Clear type and all enable bits
pin_reg_val |= (0x2 << 7); // Set type to falling edge
pin_reg_val |= (1 << 13); // Enable for PRO CPU
GPIO_PIN_REG(18) = pin_reg_val;
GPIO_STATUS_W1TC_REG = (1 << 18); // Clear any pending status
esp_intr_enable_source(ETS_GPIO_INTR_SOURCE);
esp_intr_alloc(ETS_GPIO_INTR_SOURCE,
ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_NMI,
gpio_isr_handler,
NULL,
NULL);
}
void app_main(void) {
config_gpio();
while (1) {
GPIO_OUT_W1TS_REG = (1 << 14);
vTaskDelay(pdMS_TO_TICKS(700));
GPIO_OUT_W1TC_REG = (1 << 14);
printf("PIN 18 state %lu \n", READ_INPUT(18));
vTaskDelay(pdMS_TO_TICKS(700));
}
}