Bare metal programming

daniellizarazoo
Posts: 1
Joined: Wed Jul 30, 2025 6:51 pm

Bare metal programming

Postby daniellizarazoo » 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));
    }
}

vvb333007
Posts: 71
Joined: Wed Jul 31, 2024 5:53 am
Location: Thailand
Contact:

Re: Bare metal programming

Postby vvb333007 » Fri Aug 01, 2025 4:55 am

Can somebody guide me in Interruption programming.
Code from Cadence/Tensilica may shed some light on it (it is a source code for their closed-source Xtensa Hardware Abstraction Layer):

https://chromium.googlesource.com/chrom ... rch/xtensa

There are functions to set up interrupts and handlers, but you have to find it out.
This is what ESP-IDF uses.

https://chromium.googlesource.com/chrom ... /smp/xtos/
Thanks!
Slava.

Who is online

Users browsing this forum: PetalBot and 5 guests