Hi
Thanks for replying
After a certain time trying to follow up the guide, i came up with this code
Code: Select all
#include <stdint.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#define LED_GPIO 2
#define BUTTON_GPIO 4
#define INTERRUPT_MATRIX_BASE 0x600C2000
#define GPIO_OUT_W1TS_REG 0x60004008
#define GPIO_OUT_W1TC_REG 0x6000400C
#define GPIO_ENABLE_W1TS_REG 0x60004020
#define GPIO_ENABLE_W1TC_REG 0x60004024
#define GPIO_IN_REG 0x6000403C // Registro para leer entradas
// Interrupciones
#define MTVEC_CSR_ADDR 0x305
#define MTVEC_VECTORED_MODE 0x1
// IO_MUX (entrada digital)
#define IO_MUX_BASE 0x60009000
#define IO_MUX_GPIO4_REG (IO_MUX_BASE + 0x14) // GPIO4
// GPIO Matrix (interrupciones)
#define GPIO_PIN4_REG 0x60004084
#define GPIO_CPU_INT_REG 0x60004098
#define GPIO_STATUS_W1TC_REG 0x60004044
// Macros de bits
#define FUN_IE (1 << 9)
#define GPIO_PIN_INT_TYPE_S 5
#define GPIO_PIN_INT_ENA_S 13
// Asignar source 16 (GPIO_PROCPU_INTR) a la interrupción 4 de la CPU
#define INTERRUPT_CORE0_GPIO_INTERRUPT_PRO_MAP_REG 0x600C2040
// Configuración CPU para atender la interrupción
#define INTERRUPT_CORE0_CPU_INT_TYPE_REG 0x600C20F8
#define INTERRUPT_CORE0_CPU_INT_PRI_BASE 0x600C2118 // + Num_P * 0x04
#define INTERRUPT_CORE0_CPU_INT_ENABLE_REG 0x600C2104
// Definición de WCL (World Controller)
// El registro WCL_CORE_0_MTVEC_BASE_REG debe actualizarse al cambiar mtvec .
// La dirección base del WCL es relativa a la base del System and Memory .
// Usamos una dirección conceptual/placeholder aquí:
#define WCL_BASE_ADDR 0x600D0000 // Dirección conceptual (la dirección exacta no está en las fuentes)
#define WCL_MTVEC_BASE_REG_OFFSET 0x00000004 // Offset conceptual
// Limpieza
#define INTERRUPT_CORE0_CPU_INT_CLEAR_REG 0x600C210C
//Vector de interrupciones custom
#define INTERRUPT_CORE0_INTR_STATUS_0_REG 0x600C2080
#define GPIO_STATUS_INTERRUPT 0x600C2044
#define INTERRUPT_CORE0_CPU_INT_EIP_STATUS_REG 0x600C2110
// Funciones para alterar CSR
static inline uint32_t read_csr(uint32_t csr_addr) {
uint32_t val;
asm volatile ("csrr %0, %1" : "=r"(val) : "i"(csr_addr));
return val;
}
static inline void write_csr(uint32_t csr_addr, uint32_t val) {
asm volatile ("csrw %0, %1" :: "i"(csr_addr), "r"(val));
}
//Entrada
volatile uint32_t *gpio_disable_out_reg = (volatile uint32_t *)GPIO_ENABLE_W1TC_REG; //Deshabilita la salida (es decir,abre la entrada)
volatile uint32_t *gpio_in_reg = (volatile uint32_t *)GPIO_IN_REG; //Lee la entrada
//Salida
volatile uint32_t *gpio_enable_out_reg = (volatile uint32_t *)GPIO_ENABLE_W1TS_REG; //Habilita la salida
volatile uint32_t *gpio_out_w1ts_reg = (volatile uint32_t *)GPIO_OUT_W1TS_REG; //Enciende la salida
volatile uint32_t *gpio_out_w1tc_reg = (volatile uint32_t *)GPIO_OUT_W1TC_REG; //Apaga la salida
void initialize_led(void)
{
*gpio_enable_out_reg = 1 << LED_GPIO; // Configura GPIO2 como salida
}
void initialize_button(void)
{
*gpio_disable_out_reg = 1 << BUTTON_GPIO; // Configura GPIO0 como entrada
}
// I. Configuración del Pin GPIO (Capa IO MUX y GPIO Matrix)
int interrupt_button(void)
{
*gpio_disable_out_reg = 1 << BUTTON_GPIO; // GPIO4 entrada
// (1) Habilitar entrada digital en IO_MUX
*((volatile uint32_t *)IO_MUX_GPIO4_REG) |= (1 << 9); // FUN_IE
// (2) Configurar tipo de interrupción: flanco ascendente (1)
uint32_t reg = *((volatile uint32_t *)GPIO_PIN4_REG);
reg = (reg & ~(7 << 5)) | (1 << 5) | (1 << 13);
*((volatile uint32_t *)GPIO_PIN4_REG) = reg;
return 0;
}
// II.Asignar la fuente de interrupción (GPIO4) a la interrupción 4
void map_gpio_to_interrupt(uint8_t Num_P)
{
if (Num_P < 1 || Num_P > 31) return; // Validación simple
volatile uint32_t *reg = (volatile uint32_t *)INTERRUPT_CORE0_GPIO_INTERRUPT_PRO_MAP_REG;
// Limpiar bits [4:0] y escribir Num_P
uint32_t val = *reg;
val &= ~0x1F; // borrar bits 0-4
val |= (Num_P & 0x1F);
*reg = val;
}
/// III. Configuración de la Interrupción de la CPU (Controlador de Interrupciones del CPU)
void configure_cpu_interrupt(uint8_t Num_P, uint8_t edge_or_level, uint8_t priority) {
if (Num_P < 1 || Num_P > 31) return;
if (priority < 1) priority = 1;
if (priority > 15) priority = 15;
// --- Paso 1: Tipo de interrupción ---
volatile uint32_t *type_reg = (volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_TYPE_REG;
if (edge_or_level) {
*type_reg |= (1 << Num_P); // Flanco
} else {
*type_reg &= ~(1 << Num_P); // Nivel
}
// --- Paso 2: Prioridad ---
volatile uint32_t *pri_reg = (volatile uint32_t *)(INTERRUPT_CORE0_CPU_INT_PRI_BASE + (Num_P - 1) * 4);
*pri_reg = priority;
// --- Paso 3: Habilitar interrupción ---
volatile uint32_t *enable_reg = (volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_ENABLE_REG;
*enable_reg |= (1 << Num_P);
// --- Paso 4: Habilitación global MIE ---
uint32_t mie;
asm volatile ("csrr %0, mstatus" : "=r"(mie));
mie |= (1 << 3); // Bit MIE = Machine Interrupt Enable
asm volatile ("csrw mstatus, %0" :: "r"(mie));
asm volatile ("fence"); // asegurar la propagación de escrituras
}
// (IV) Limpiar el estado
void clear_gpio_interrupt(uint8_t gpio_num, uint8_t cpu_num, uint8_t is_edge) {
// --- Limpiar interrupción GPIO ---
*((volatile uint32_t *)GPIO_STATUS_W1TC_REG) = (1 << gpio_num);
// --- Limpiar interrupción CPU (si es flanco) ---
if (is_edge) {
volatile uint32_t *cpu_clear_reg = (volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_CLEAR_REG;
*cpu_clear_reg |= (1 << cpu_num); // poner 1
*cpu_clear_reg &= ~(1 << cpu_num); // resetear a 0
}
}
// int read_button(void)
// {
// return ((*gpio_in_reg >> BUTTON_GPIO) & 0x1); // 1 si presionado, 0 si no
// }
//Modificar vector de interrupciones
// void gpio_isr(void){
// }
void toggle_led(void)
{
*gpio_out_w1tc_reg = 1 << LED_GPIO; // Apaga LED
for (volatile int i = 0; i < 100000; i++); // Delay simple
*gpio_out_w1ts_reg = 1 << LED_GPIO; // Enciende LED
for (volatile int i = 0; i < 100000; i++); // Delay simple
}
void GPIO4_ISR(void) {
clear_gpio_interrupt(4, 4, 1); // Limpiar interrupción
toggle_led(); // Alternar LED
}
int app_main(void)
{
// 0 Inicialización hardware
initialize_led();
initialize_button();
//---1 Configuración del pin GPIO4 como entrada con interrupción
interrupt_button();
//---2. Asignar GPIO4 a la interrupción 4
map_gpio_to_interrupt(16); // Fuente 16 = GPIO_PROCPU_INTR
//--3. Configurar la interrupción 4:
// edge_or_level = 1 (flanco), priority = 1 (baja)
configure_cpu_interrupt(16, 1, 1);
printf("CONFIGURED\n");
while (1) {
//esp_task_wdt_reset(); // Resetear el watchdog
volatile uint32_t *gpio_intr_status = (volatile uint32_t *)GPIO_STATUS_INTERRUPT; // registro R/W/SS
uint32_t pending = *gpio_intr_status;
esp_rom_printf("GPIO interrupt status: 0x%08lX\n", (unsigned long)pending);
if (pending & (1 << 16)) {
printf("GPIO4 interrupt pending!\n");
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
// while(1) {
// uint32_t pending_gpio = *((volatile uint32_t *)GPIO_STATUS_W1TC_REG);
// if (pending_gpio & (1 << 4)) {
// printf("GPIO4 interrupt pending at peripheral level\n");
// }
// }
return 0;
}
For now, i don't know
1. How can i see if i attach correctly the interrupt
2. how to create the ISR thah te ESP-IDF API does
Any comment is much apreciated