Interrupt inputs are a limited resource on the ESP32, and initializing certain features requires interrupt inputs to be attached to the peripherals. Just like other resources (such as RAM), the program can run out of the interrupt inputs if it uses multiple features at once.
The good news is that it is usually possible to make everything work by utilizing higer level (level 2 or 3) interrupts and possibly by using shared interrupts.
Debugging interrupt allocations
DEBUG_INT_ALLOC_DECISIONS
There is no Kconfig option or another way to enable this without changing IDF code (yet), so you need to edit this file: esp-idf/components/esp_hw_support/intr_alloc.c
Uncomment this line:
// #define DEBUG_INT_ALLOC_DECISIONS
Also set “log level” option in menuconfig to “Debug”
In the VS Code “TERMINAL” window, enter: idf.py menuconfig
(You may need to use CTRL + ] to end its current mode and get its command prompt first)
This will bring up the menuconfig UI within the terminal window.
Use the J & K keys for UP/Down
Enable the verbose debug level: “Component config -> Log output -> Default log verbosity” and set it to “Verbose” (instead of its default level “Info”).
Save and quit
Then give your project a full clean and build the project again. When you launch it you will get lots of lines with a “intr_alloc” log tag. These show you which interrupts are being allocated.
Changing peripherals from using a level 1 irq (free up level 1 irqs)
I2C
i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0); //(i2c_num, mode, slv_rx_buf_len, slv_tx_buf_len, intr_alloc_flags)
//i2c_driver_install(i2c_port, i2c_config.mode, 0, 0, ESP_INTR_FLAG_LOWMED); //<<< Alternative version using non dedicated level 1 interrupt (if you have issues running out of level 1 interrupts)
TWAI / canbus
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_CANBUS_TX, GPIO_CANBUS_RX, TWAI_MODE_NORMAL);
g_config.intr_flags = ESP_INTR_FLAG_LOWMED; //Optional - move canbus irq to free up the default level 1 IRQ it will take up
SPI master and slave
This can be set by intr_flags member of spi_bus_config_t, which is used in the call to spi_bus_initialize.
spi_bus_config_t SpiBusConfig={
.miso_io_num = BMI088_SPI_PIN_MISO,
.mosi_io_num = BMI088_SPI_PIN_MOSI,
.sclk_io_num = BMI088_SPI_PIN_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = BMI088_SPI_MAX_TRANSFER_SIZE_BYTES,
.intr_flags = ESP_INTR_FLAG_LOWMED, //<<<Optional, include to ensure SPI doesn't consume a level 1 irq if you are short of irqs
};
UART
If you are using the UART driver API, driver/uart.h, it can be set using the last argument of uart_driver_install, intr_alloc_flags.
If you are using UART only for console output without calling uart_driver_install, then it doesn’t occupy an interrupt.