ESP-IDF学习笔记-错误处理

同STM32HAL库的各种错误状态码一样,ESP-IDF中也有不同的错误码以及相应的错误处理方法,这给出基本的使用。

首先放上官方文档

一,错误的分类

ESP32中主要有两类错误:

  1. 可恢复错误

可用错误状态码表示,使用 throw 关键字抛出的 C++ 异常。

  1. 不可恢复(严重)错误

断言失败:(使用 assert 宏或者其它类似方法,可参考 Assertions)或者直接调用 abort() 函数造成的错误

CPU 异常:访问受保护的内存区域、非法指令等

系统级检查:看门狗超时、缓存访问错误、堆栈溢出、堆栈粉碎、堆栈损坏等

二,错误码与错误消息

在ESP-IDF中,错误码的类型是esp_err_t,本质是带符号整型。其中表示没有错误的定义是:ESP_OK具体定义为0。

对于一个具体的错误,错误码常常以ESP_ERR_XXX形式呈现,常见的错误码在esp_err.h中已经定义好了,各个组件也可以自定义。

得到整型的错误码可以使用esp_err_to_name()或者esp_err_to_name_r()函数(esp_err.h)将其转换为字符串(返回值是const char *),这两个函数的区别主要在于当没有匹配的错误时,是否用 标准 POSIX 错误代码 进行解释。

三,常用宏

  • ESP_ERROR_CHECK

该宏定义在esp_err.h中。功能与assert相似,但是会检测错误值并打印错误信息,最后调用abort()

通常错误信息如下:

1
2
3
4
5
6
7
ESP_ERROR_CHECK failed: esp_err_t 0x107 (ESP_ERR_TIMEOUT) at 0x400d1fdf

file: "/Users/user/esp/example/main/main.c" line 20
func: app_main
expression: sdmmc_card_init(host, &card)

Backtrace: 0x40086e7c:0x3ffb4ff0 0x40087328:0x3ffb5010 0x400d1fdf:0x3ffb5030 0x400d0816:0x3ffb5050
  • ESP_ERROR_CHECK_WITHOUT_ABORT

该宏定义在esp_err.h中。功能与ESP_ERROR_CHECK一样,但不会调用abort()

以下宏定义在esp_check.h

  • ESP_RETURN_ON_ERROR

宏 ESP_RETURN_ON_ERROR 用于错误码检查, 如果错误码不等于 ESP_OK, 该宏会打印错误信息,并使原函数立刻返回。

  • ESP_GOTO_ON_ERROR

宏 ESP_GOTO_ON_ERROR 用于错误码检查, 如果错误码不等于 ESP_OK, 该宏会打印错误信息,将局部变量 ret 赋值为该错误码, 并使原函数跳转至给定的 goto_tag.

  • ESP_RETURN_ON_FALSE

宏 ESP_RETURN_ON_FALSE 用于条件检查, 如果给定条件不等于 true, 该宏会打印错误信息,并使原函数立刻返回,返回值为给定的 err_code.

  • ESP_GOTO_ON_FALSE

宏 ESP_GOTO_ON_FALSE 用于条件检查, 如果给定条件不等于 true, 该宏会打印错误信息,将局部变量 ret 赋值为给定的 err_code, 并使原函数跳转至给定的 goto_tag.

ESP_RETURN_xx 和 ESP_GOTO_xx 宏不可以在中断服务程序里被调用。

使用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static const char* TAG = "Test";

esp_err_t test_func(void)
{
esp_err_t ret = ESP_OK;

ESP_ERROR_CHECK(x); // err message printed if `x` is not `ESP_OK`, and then `abort()`.
ESP_ERROR_CHECK_WITHOUT_ABORT(x); // err message printed if `x` is not `ESP_OK`, without `abort()`.
ESP_RETURN_ON_ERROR(x, TAG, "fail reason 1"); // err message printed if `x` is not `ESP_OK`, and then function returns with code `x`.
ESP_GOTO_ON_ERROR(x, err, TAG, "fail reason 2"); // err message printed if `x` is not `ESP_OK`, `ret` is set to `x`, and then jumps to `err`.
ESP_RETURN_ON_FALSE(a, err_code, TAG, "fail reason 3"); // err message printed if `a` is not `true`, and then function returns with code `err_code`.
ESP_GOTO_ON_FALSE(a, err_code, err, TAG, "fail reason 4"); // err message printed if `a` is not `true`, `ret` is set to `err_code`, and then jumps to `err`.

err:
// clean up
return ret;
}

如果 Kconfig 中的 CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT 选项被打开, CHECK 宏将不会打印错误信息,其他功能不变。

四,错误处理

根据错误码恢复

用变量储存错误码,在代码中判断错误码类型,根据类型不同尝试恢复。或者使用上面用到的CHECK宏。

转化为不可恢复错误

使用ESP_ERROR_CHECK处理返回值。

1
ESP_ERROR_CHECK(spi_bus_initialize(host, bus_config, dma_chan));

五,严重错误

以下情况为不可恢复的严重错误,程序会中断重启。

  • CPU 异常:非法指令,加载/存储时的内存对齐错误,加载/存储时的访问权限错误,双重异常。

  • 系统级检查错误:

    中断看门狗 超时

    任务看门狗 超时(只有开启 CONFIG_ESP_TASK_WDT_PANIC 后才会触发严重错误)

    高速缓存访问错误

    内存保护故障

    掉电检测事件

    堆栈溢出

    堆栈粉碎保护检查

    堆完整性检查

    未定义行为清理器 (UBSAN) 检查

  • 使用 assert、configASSERT 等类似的宏断言失败。

官方文档给出了参考解决,这里先待补,等以后接触后继续。