feat(system): add esp_intr_dump function to debug interrupt alloc

esp_intr_dump function can be used to print the list of allocated and
free interrupts. It can be used as a debugging aid when interrupt
allocation fails.
This commit is contained in:
Ivan Grokhotkov 2023-05-22 20:57:31 +02:00
parent 0ac1ee4358
commit 621afc48b1
No known key found for this signature in database
GPG Key ID: 1E050E141B280628
2 changed files with 92 additions and 0 deletions

View File

@ -8,6 +8,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "esp_err.h"
#ifdef __cplusplus
@ -307,6 +308,13 @@ static inline int esp_intr_flags_to_level(int flags)
return __builtin_ffs((flags & ESP_INTR_FLAG_LEVELMASK) >> 1) + 1;
}
/**
* @brief Dump the status of allocated interrupts
* @param stream The stream to dump to, if NULL then stdout is used
* @return ESP_OK on success
*/
esp_err_t esp_intr_dump(FILE *stream);
/**@}*/

View File

@ -22,6 +22,9 @@
#include "esp_attr.h"
#include "esp_cpu.h"
#include "esp_private/rtc_ctrl.h"
#include "soc/interrupts.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h"
#if !CONFIG_FREERTOS_UNICORE
#include "esp_ipc.h"
@ -902,3 +905,84 @@ void IRAM_ATTR esp_intr_disable_source(int inum)
{
esp_cpu_intr_disable(1 << inum);
}
esp_err_t esp_intr_dump(FILE *stream)
{
if (stream == NULL) {
stream = stdout;
}
#ifdef CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
const int cpu_num = 1;
#else
const int cpu_num = SOC_CPU_CORES_NUM;
#endif
int general_use_ints_free = 0;
int shared_ints = 0;
for (int cpu = 0; cpu < cpu_num; ++cpu) {
fprintf(stream, "CPU %d interrupt status:\n", cpu);
fprintf(stream, " Int Level Type Status\n");
for (int i_num = 0; i_num < 32; ++i_num) {
fprintf(stream, " %2d ", i_num);
esp_cpu_intr_desc_t intr_desc;
esp_cpu_intr_get_desc(cpu, i_num, &intr_desc);
bool is_general_use = true;
vector_desc_t *vd = find_desc_for_int(i_num, cpu);
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
fprintf(stream, " %d %s ",
intr_desc.priority,
intr_desc.type == ESP_CPU_INTR_TYPE_EDGE ? "Edge " : "Level");
is_general_use = (intr_desc.type == ESP_CPU_INTR_TYPE_LEVEL) && (intr_desc.priority <= XCHAL_EXCM_LEVEL);
#else // SOC_CPU_HAS_FLEXIBLE_INTC
if (vd == NULL) {
fprintf(stream, " * * ");
} else {
// esp_cpu_intr_get_* functions need to be extended with cpu parameter.
// Showing info for the current cpu only, in the meantime.
if (esp_cpu_get_core_id() == cpu) {
fprintf(stream, " %d %s ",
esp_cpu_intr_get_priority(i_num),
esp_cpu_intr_get_type(i_num) == ESP_CPU_INTR_TYPE_EDGE ? "Edge " : "Level");
} else {
fprintf(stream, " ? ? ");
}
}
#endif // SOC_CPU_HAS_FLEXIBLE_INTC
if (intr_desc.flags & ESP_CPU_INTR_DESC_FLAG_RESVD) {
fprintf(stream, "Reserved");
} else if (intr_desc.flags & ESP_CPU_INTR_DESC_FLAG_SPECIAL) {
fprintf(stream, "CPU-internal");
} else {
if (vd == NULL || (vd->flags & (VECDESC_FL_RESERVED | VECDESC_FL_NONSHARED | VECDESC_FL_SHARED)) == 0) {
fprintf(stream, "Free");
if (is_general_use) {
++general_use_ints_free;
} else {
fprintf(stream, " (not general-use)");
}
} else if (vd->flags & VECDESC_FL_RESERVED) {
fprintf(stream, "Reserved (run-time)");
} else if (vd->flags & VECDESC_FL_NONSHARED) {
fprintf(stream, "Used: %s", esp_isr_names[vd->source]);
} else if (vd->flags & VECDESC_FL_SHARED) {
fprintf(stream, "Shared: ");
for (shared_vector_desc_t *svd = vd->shared_vec_info; svd != NULL; svd = svd->next) {
fprintf(stream, "%s ", esp_isr_names[svd->source]);
}
++shared_ints;
} else {
fprintf(stream, "Unknown, flags = 0x%x", vd->flags);
}
}
fprintf(stream, "\n");
}
}
fprintf(stream, "Interrupts available for general use: %d\n", general_use_ints_free);
fprintf(stream, "Shared interrupts: %d\n", shared_ints);
return ESP_OK;
}