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.

USEFUL?
We benefit hugely from resources on the web so we decided we should try and give back some of our knowledge and resources to the community by opening up many of our company’s internal notes and libraries through mini sites like this. We hope you find the site helpful.
Please feel free to comment if you can add help to this page or point out issues and solutions you have found, but please note that we do not provide support on this site. If you need help with a problem please use one of the many online forums.

Comments

Your email address will not be published. Required fields are marked *