Page 1 of 1

ESP32 Register Level Interrupt Code doesn't work

Posted: Sat Oct 11, 2025 11:05 am
by leopard
I need to setup a circuit that reads a gpio button and turn on/off the another gpio led according to the signal of the button using interrupts. I started to write register level coding about configuration and enable the GPIO pinsi which works correct, however, when it comes to interrupts, my functions doesn't work and even the ISR function even weren't be triggered. I cannot find where the missing part is. (Value of the GPIO->GPIO_STATUS_REG is always 0x00000000)

main.c:

Code: Select all

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "esp_log.h" 
#include "sdkconfig.h"
#include "esp32custom.h" 
#include "gpio.h"
#include "esp_intr_alloc.h"

#define CONFIG_FREERTOS_HZ 1000 

volatile GPIO_States current_led_state = GPIO_Reset; 


void IRAM_ATTR GPIO_ISR_Handler(void* arg)
{

    if (current_led_state == GPIO_Reset) {
        GPIO_WritePin(19, GPIO_Set, GPIO);  
        current_led_state = GPIO_Set;
    } else {
        GPIO_WritePin(19, GPIO_Reset, GPIO); 
        current_led_state = GPIO_Reset;
    }

    GPIO_Interrupt_Clear(5);
 
}


void app_main(void) {
  
    GPIO_Init_TypeDef gpio_button = {
        .FUN_DRV = FUN_DRV_MED,
        .mode = 0,
        .FUN_IE = FUN_IE_OPEN,
        .MCU_SEL = MCU_SEL_FUNC0,
        .FUN_WPD = FUN_WPD_CLOSE,
        .FUN_WPU = FUN_WPU_OPEN,
    };

    GPIO_Init(&gpio_button, GPIO5, 5);
    GPIO_Interrupt_Config(5);
    GPIO_Init_TypeDef gpio_led = {
        .FUN_DRV = FUN_DRV_MED,
        .mode = 1,
        .FUN_IE = FUN_IE_CLOSE,
        .MCU_SEL = MCU_SEL_FUNC0,
        .FUN_WPD = FUN_WPD_CLOSE,
        .FUN_WPU = FUN_WPU_CLOSE,
    };

    GPIO_Init(&gpio_led, GPIO19, 19);
    GPIO_WritePin(19, GPIO_Reset, GPIO); 




    esp_intr_alloc(ETS_GPIO_INTR_SOURCE, 
                   ESP_INTR_FLAG_IRAM, 
                   GPIO_ISR_Handler, 
                   (void*)5, 
                   NULL);


  while(1) {
    /*
    GPIO_States button_state = GPIO_ReadPin(5);

        if (button_state == GPIO_Reset) { // GPIO_Reset (LOW) ise
            GPIO_WritePin(19, GPIO_Set, GPIO); // LED'i Yak (HIGH)
        } 
        else { 
            GPIO_WritePin(19, GPIO_Reset, GPIO); // LED'i Söndür (LOW)
        }
      */  
        vTaskDelay(pdMS_TO_TICKS(10)); 
  }
}
gpio.h:

Code: Select all


#ifndef INC_ESP32_GPIO
#define INC_ESP32_GPIO

#include "esp32custom.h"

#define MCU_SEL_FUNC0 0x0U
#define MCU_SEL_FUNC1 0x1U
#define MCU_SEL_FUNC2 0x2U

#define FUN_DRV_LOW 0x0U
#define FUN_DRV_MED 0x1U
#define FUN_DRV_HIGH 0x2U
#define FUN_DRV_ULTRA 0x3U

#define FUN_IE_CLOSE 0x0U
#define FUN_IE_OPEN 0x1U

#define FUN_WPU_CLOSE 0x0U
#define FUN_WPU_OPEN 0x1U

#define FUN_WPD_CLOSE 0x0U
#define FUN_WPD_OPEN 0x1U

#define PIN_CTRL    &IOMUX->PIN_CTRL
#define GPIO36      &IOMUX->GPIO36_REG
#define GPIO37      &IOMUX->GPIO37_REG
#define GPIO38      &IOMUX->GPIO38_REG
#define GPIO39      &IOMUX->GPIO39_REG
#define GPIO34      &IOMUX->GPIO34_REG
#define GPIO35      &IOMUX->GPIO35_REG
#define GPIO32      &IOMUX->GPIO32_REG
#define GPIO33      &IOMUX->GPIO33_REG
#define GPIO25      &IOMUX->GPIO25_REG
#define GPIO26      &IOMUX->GPIO26_REG
#define GPIO27      &IOMUX->GPIO27_REG
#define MTMS        &IOMUX->MTMS_REG
#define MTDI        &IOMUX->MTDI_REG
#define MTCK        &IOMUX->MTCK_REG
#define MTDO        &IOMUX->MTDO_REG
#define GPIO2       &IOMUX->GPIO2_REG
#define GPIO0       &IOMUX->GPIO0_REG
#define GPIO4       &IOMUX->GPIO4_REG
#define GPIO16      &IOMUX->GPIO16_REG
#define GPIO17      &IOMUX->GPIO17_REG
#define SD_DATA2    &IOMUX->SD_DATA2_REG
#define SD_DATA3    &IOMUX->SD_DATA3_REG
#define SD_CMD      &IOMUX->SD_CMD_REG
#define SD_CLK      &IOMUX->SD_CLK_REG
#define SD_DATA0    &IOMUX->SD_DATA0_REG
#define SD_DATA1    &IOMUX->SD_DATA1_REG
#define GPIO5       &IOMUX->GPIO5_REG
#define GPIO18      &IOMUX->GPIO18_REG
#define GPIO19      &IOMUX->GPIO19_REG
#define GPIO20      &IOMUX->GPIO20_REG
#define GPIO21      &IOMUX->GPIO21_REG
#define GPIO22      &IOMUX->GPIO22_REG
#define U0RXD       &IOMUX->U0RXD_REG
#define U0TXD       &IOMUX->U0TXD_REG
#define GPIO23      &IOMUX->GPIO23_REG

typedef enum
{

    GPIO_Set = 0x1U,
    GPIO_Reset = !GPIO_Set

} GPIO_States;

typedef struct
{
    uint32_t MCU_SEL;
    uint32_t FUN_DRV;
    uint32_t FUN_IE;
    uint32_t FUN_WPU;
    uint32_t FUN_WPD;
    uint32_t mode;
} GPIO_Init_TypeDef;

void GPIO_WritePin(uint32_t pinNumber, GPIO_States state, GPIO_TYPEDEF *GPIO_Type);
void GPIO_Init(GPIO_Init_TypeDef *GPIO_Init, uint32_t *selected_pin, uint32_t pinNumber);
void GPIO_Interrupt_Config(uint32_t selected_pin);
void GPIO_Interrupt_Clear(uint32_t input_pin);

GPIO_States GPIO_ReadPin(uint32_t pinNumber);

#endif

gpio.c:

Code: Select all

#include "gpio.h"
#include <stdio.h>
/**
 * @brief   Arrange the pin status according to the parameters, if state equals to SET, the pin set to LOGIC-HIGH.
 * 
 * @param   pinNumber: Name of the pin as integer.
 * @param   state: Selection between LOGIC-HIGH (GPIO_Set) or LOGIC-LOW (GPIO_RESET).
 * @param   GPIO_Type: Pointer to the GPIO_TypeDef structure.
 * 
 * @retval  None
 */
void GPIO_WritePin(uint32_t pinNumber, GPIO_States state, GPIO_TYPEDEF *GPIO_Type)
{
    if (state == GPIO_Set)
    {
        if (pinNumber > 31)
        {
            GPIO_Type->GPIO_OUT1_W1TS_REG |= (0x1U << (pinNumber - 32));
        }
        else
        {
            GPIO_Type->GPIO_OUT_W1TS_REG |= (0x1U << pinNumber);
        }
    }
    else
    {
        if (pinNumber > 31)
        {
            GPIO_Type->GPIO_OUT1_W1TC_REG |=(0x1U << (pinNumber - 32));
        }
        else
        {
            GPIO_Type->GPIO_OUT_W1TC_REG |=(0x1U << pinNumber);
            
        }
    }
}

/**
 * @brief  Belirtilen GPIO pininin o anki durumunu (HIGH/LOW) okur.
 *
 * @param  pinNumber: Durumu okunacak pinin numarası (0-39).
 * @param  GPIO_Type: GPIO_TYPEDEF yapısının adresini gösteren işaretçi.
 *
 * @retval GPIO_States: GPIO_Set (HIGH) veya GPIO_Reset (LOW) değeri.
 */
GPIO_States GPIO_ReadPin(uint32_t pinNumber)
{
    uint32_t pin_value;

    if (pinNumber > 31)
    {
        pin_value = GPIO->GPIO_IN1_REG;
        if ((pin_value & (0x1U << (pinNumber - 32))) != 0)
        {
            return GPIO_Set;
        }
    }
    else
    {
        pin_value = GPIO->GPIO_IN_REG;
        if ((pin_value & (0x1U << pinNumber)) != 0)
        {
            return GPIO_Set;
        }
    }

    return GPIO_Reset;
}


/**
 * @brief  Initialization of specified GPIO pin according to the user settings.
 *
 * @param  GPIO_Init_TypeDef: The struct includes user's configration.
 * @param  selected_pin: Pointer specified to specific GPIO pin.
 * @param  pinNumber: Name of the pin as integer.
 *
 * @retval None
 */
void GPIO_Init(GPIO_Init_TypeDef *GPIO_Init, uint32_t *selected_pin, uint32_t pinNumber)
{
    
    uint32_t temp_reg = *selected_pin;

    temp_reg &= ~(0x7 << 12);
    temp_reg |= (GPIO_Init->MCU_SEL << 12);

    temp_reg &= ~(0x3 << 10);
    temp_reg |= (GPIO_Init->FUN_DRV << 10);

    temp_reg &= ~(0x1 << 9);
    temp_reg |= (GPIO_Init->FUN_IE << 9);

    temp_reg &= ~(0x1 << 8);
    temp_reg |= (GPIO_Init->FUN_WPU << 8);

    temp_reg &= ~(0x1 << 7);
    temp_reg |= (GPIO_Init->FUN_WPD << 7);

    *selected_pin = temp_reg;

     if (GPIO_Init->mode == 1) { 
        if (pinNumber > 31) {
            GPIO->GPIO_ENABLE1_W1TS_REG |= (1 << (pinNumber - 32));
        } else {
            GPIO->GPIO_ENABLE_W1TS_REG |= (1 << pinNumber);
        }
    } else { 
        if (pinNumber > 31) {
            GPIO->GPIO_ENABLE1_W1TC_REG |= (1 << (pinNumber - 32));
        } else {
            GPIO->GPIO_ENABLE_W1TC_REG |= (1 << pinNumber);
        }
    }
}

void GPIO_Interrupt_Config(uint32_t selected_pin){
    
    uint32_t temp_pin_reg = GPIO->GPIO_PIN_REG[selected_pin];
    temp_pin_reg &= ~((0x7 << 7) | (0xF << 13)); // Clear existing bits
    temp_pin_reg |= (0x3 << 7); // Rising edge trigger (value 1)
        temp_pin_reg |= (1 << 13);  // Enable interrupt mask
    temp_pin_reg |= (1 << 15);// Enable PRO CPU interrupt (bit 15)
    GPIO->GPIO_PIN_REG[selected_pin] = temp_pin_reg;
    printf("SECOND:");
    GPIO->GPIO_STATUS_W1TC_REG = (1U << selected_pin);
}

void GPIO_Interrupt_Clear(uint32_t selected_pin)
{
    GPIO->GPIO_STATUS_W1TC_REG |= (1 << (selected_pin));
}
some definitions from esp32custom.h:

Code: Select all

#include <stdint.h>

#ifndef INC_ESP32_
#define INC_ESP32_



#define SPIO_BASE_ADDR              (0x3FF43000UL)
#define UART0_BASE_ADDR             (0x3FF40000UL)
#define SRAM1_DATA_BASE_ADDR        (0x3FFE0000UL)
#define SRAM1_INST_BASE_ADDR        (0x400A0000UL)
#define SRAM2_DATA_BASE_ADDR        (0x3FFAE000UL)


/*
 *  PERIPHERAL BASE ADDRESSES
 */

#define PERIPHERAL_BASE_ADDR        (0x3FF00000UL)

#define DPORT_OFFSET         (0x0000UL)
#define UART0_OFFSET         (0x4000UL)
#define SPI1_OFFSET          (0x42000UL)
#define SPI0_OFFSET          (0x43000UL)
#define SPI2_OFFSET          (0x64000UL)
#define GPIO_OFFSET          (0x44000UL)
#define RTC_OFFSET           (0x48000UL)
#define IOMUX_OFFSET         (0x49000UL)
#define SDIO_SLAVE_OFFSET    (0x4B000UL)
#define UDMA1_OFFSET         (0x4C000UL)
#define I2S0_OFFSET          (0x4F000UL)
#define UART1_OFFSET         (0x50000UL)
#define I2C0_OFFSET          (0x53000UL)



#define DPORT_BASE_ADDR      (PERIPHERAL_BASE_ADDR + DPORT_OFFSET)
#define UART0_BASE_ADDR      (PERIPHERAL_BASE_ADDR + UART0_OFFSET)
#define SPI1_BASE_ADDR       (PERIPHERAL_BASE_ADDR + SPI1_OFFSET)
#define SPI0_BASE_ADDR       (PERIPHERAL_BASE_ADDR + SPI0_OFFSET)
#define SPI2_BASE_ADDR       (PERIPHERAL_BASE_ADDR + SPI2_OFFSET)
#define GPIO_BASE_ADDR       (PERIPHERAL_BASE_ADDR + GPIO_OFFSET)
#define RTC_BASE_ADDR        (PERIPHERAL_BASE_ADDR + RTC_OFFSET)
#define IOMUX_BASE_ADDR      (PERIPHERAL_BASE_ADDR + IOMUX_OFFSET)
#define SDIO_SLAVE_BASE_ADDR (PERIPHERAL_BASE_ADDR + SDIO_SLAVE_OFFSET)
#define UDMA1_BASE_ADDR      (PERIPHERAL_BASE_ADDR + UDMA1_OFFSET)
#define I2S0_BASE_ADDR       (PERIPHERAL_BASE_ADDR + I2S0_OFFSET)
#define UART1_BASE_ADDR      (PERIPHERAL_BASE_ADDR + UART1_OFFSET)
#define I2C0_BASE_ADDR       (PERIPHERAL_BASE_ADDR + I2C0_OFFSET)

typedef struct
{  
    volatile uint32_t reserved;                     // 0x3FF4_4000
    volatile uint32_t GPIO_OUT_REG;                 // 0x3FF4_4004
    volatile uint32_t GPIO_OUT_W1TS_REG;            // 0x3FF4_4008
    volatile uint32_t GPIO_OUT_W1TC_REG;            // 0x3FF4_400C
    volatile uint32_t GPIO_OUT1_REG;                // 0x3FF4_4010 ...
    volatile uint32_t GPIO_OUT1_W1TS_REG;
    volatile uint32_t GPIO_OUT1_W1TC_REG;
    volatile uint32_t reserved0;
    volatile uint32_t GPIO_ENABLE_REG;
    volatile uint32_t GPIO_ENABLE_W1TS_REG;
    volatile uint32_t GPIO_ENABLE_W1TC_REG;
    volatile uint32_t GPIO_ENABLE1_REG;
    volatile uint32_t GPIO_ENABLE1_W1TS_REG;
    volatile uint32_t GPIO_ENABLE1_W1TC_REG;
    volatile uint32_t GPIO_STRAP_REG;
    volatile uint32_t GPIO_IN_REG;
    volatile uint32_t GPIO_IN1_REG;
    volatile uint32_t GPIO_STATUS_REG; 
    volatile uint32_t GPIO_STATUS_W1TS_REG;
    volatile uint32_t GPIO_STATUS_W1TC_REG;
    volatile uint32_t GPIO_STATUS1_REG;
    volatile uint32_t GPIO_STATUS1_W1TS_REG;
    volatile uint32_t GPIO_STATUS1_W1TC_REG;
    volatile uint32_t reserved1;
    volatile uint32_t GPIO_ACPU_INT_REG;
    volatile uint32_t GPIO_ACPU_NMI_INT_REG;
    volatile uint32_t GPIO_PCPU_INT_REG;
    volatile uint32_t GPIO_PCPU_NMI_INT_REG;
    volatile uint32_t GPIO_ACPU_INT1_REG;
    volatile uint32_t GPIO_ACPU_NMI_INT1_REG;
    volatile uint32_t GPIO_PCPU_INT1_REG;
    volatile uint32_t GPIO_PCPU_NMI_INT1_REG;
    volatile uint32_t reserved2;
    volatile uint32_t GPIO_PIN_REG[40];
    volatile uint32_t reserved3;
    volatile uint32_t reserved4;
    volatile uint32_t GPIO_FUNC_IN_SEL_CFG_REG[256];
    volatile uint32_t GPIO_FUNC_OUT_SEL_CFG_REG[256];

} GPIO_TYPEDEF;
#define GPIO ((GPIO_TYPEDEF *) GPIO_BASE_ADDR)
typedef struct {
    volatile uint32_t PIN_CTRL;
    volatile uint32_t GPIO36_REG;
    volatile uint32_t GPIO37_REG;
    volatile uint32_t GPIO38_REG;
    volatile uint32_t GPIO39_REG;
    volatile uint32_t GPIO34_REG;
    volatile uint32_t GPIO35_REG;
    volatile uint32_t GPIO32_REG;
    volatile uint32_t GPIO33_REG;
    volatile uint32_t GPIO25_REG;
    volatile uint32_t GPIO26_REG;
    volatile uint32_t GPIO27_REG;
    volatile uint32_t MTMS_REG;
    volatile uint32_t MTDI_REG;
    volatile uint32_t MTCK_REG;
    volatile uint32_t MTDO_REG;
    volatile uint32_t GPIO2_REG;
    volatile uint32_t GPIO0_REG;
    volatile uint32_t GPIO4_REG;
    volatile uint32_t GPIO16_REG;
    volatile uint32_t GPIO17_REG;
    volatile uint32_t SD_DATA2_REG;
    volatile uint32_t SD_DATA3_REG;
    volatile uint32_t SD_CMD_REG;
    volatile uint32_t SD_CLK_REG;
    volatile uint32_t SD_DATA0_REG;
    volatile uint32_t SD_DATA1_REG;
    volatile uint32_t GPIO5_REG;
    volatile uint32_t GPIO18_REG;
    volatile uint32_t GPIO19_REG;
    volatile uint32_t GPIO20_REG;
    volatile uint32_t GPIO21_REG;
    volatile uint32_t GPIO22_REG;
    volatile uint32_t U0RXD_REG;
    volatile uint32_t U0TXD_REG;
    volatile uint32_t GPIO23_REG;

} IOMUX_TYPEDEF;

#define IOMUX ((IOMUX_TYPEDEF*) IOMUX_BASE_ADDR)

typedef struct 
{
    volatile uint32_t DPORT_CPU_INTR_FROM_CPU[4]; //0x3FF000DC TO 0X3FF000E8
    volatile uint32_t DPORT_PRO_INTR_STATUS_REG[3]; //0X3FF000EC TO 0X3FF000F4
    volatile uint32_t DPORT_APP_INTR_STATUS_REG[3]; //0X3FF000F8 TO 0X3FF00100
    volatile uint32_t reserved[22]; //0X3FF00104 TO 0X3FF00158
    volatile uint32_t DPORT_PRO_GPIO_INTERRUPT_MAP_REG; //0X3FF0015C

    /* data */
} DPort_TypeDef;


#define DPORT ((DPort_TypeDef*) 0x3FF000DC)