1. 整体方案
本仓库基于 MicroPython for ESP32(ESP32 port)与 ESP-IDF v5.x,错误处理分为两个层级:
C 层(编译进固件):位于
firmware/port/builtins/(ESP32 板型)和esp32s3/firmware/builtins/(ESP32-S3 板型),通过 MicroPython 的mp_raise_*API 抛出 Python 异常。Python 层(运行时加载):位于
firmware/port/modules/、esp32s3/firmware/boards/*/modules/以及docs/examples/,使用try/except捕获OSError、ValueError等标准异常,部分模块还自定义了 Exception 子类。
项目没有统一的错误码枚举或中间件式错误处理器;错误以“底层 C 抛异常 → 上层 Python try/except 捕获”的方式自底向上传播。
2. C 层错误模型
2.1 使用的 MicroPython 异常类型
mp_raise_OSError(-ret):用于 I/O 类错误,将 ESP-IDF 返回的负 errno 转换为 PythonOSError。典型位置:esp32s3/firmware/builtins/machine_i2c_extmod.c中所有 I2C 读写失败路径(如machine_i2c_start、machine_i2c_stop、machine_i2c_readinto、machine_i2c_write、machine_i2c_readfrom、machine_i2c_writeto、machine_i2c_writevto等)。这是 I2C 子系统的统一错误出口。mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("...")):用于语义性错误,如machine_i2c_init/start/stop/read/write在对应函数指针为 NULL 时抛出OSError("I2C operation not supported")。mp_raise_ValueError(...)/mp_raise_msg_varg(&mp_type_ValueError, ...):用于参数校验错误,如machine_pin.c中的invalid pin、pin can only be input、bad wake value、no resources、invalid pin for wake;machine_i2c.c中的I2C(%d) doesn't exist;modmachine.c中machine_freq对非允许频率抛出frequency must be 20MHz, 40MHz, 80Mhz, 160MHz or 240MHz。mp_raise_TypeError/mp_raise_RuntimeError:在modmachine.c的machine_sleep_helper中,当触摸唤醒配置失败时抛出RuntimeError("esp_sleep_enable_touchpad_wakeup() failed")。
2.2 错误来源映射
C 文件 |
主要职责 |
典型错误 |
|---|---|---|
|
通用 machine.I2C 协议绑定 |
I2C 操作不支持、硬件返回负 errno |
|
硬件 I2C 实例化与参数校验 |
无效 I2C id |
|
GPIO Pin 构造与 irq/wake 配置 |
无效引脚、模式不兼容、唤醒资源冲突 |
|
系统级功能(freq/sleep/reset/unique_id) |
非法频率、睡眠唤醒失败、软复位 |
2.3 重启与恢复
machine_reset():调用esp_restart()直接硬重启。machine_soft_reset():设置pyexec_system_exit = PYEXEC_FORCED_EXIT并抛出SystemExit,实现 MicroPython 解释器级软复位。machine_reset_cause():将 ESP-IDF 的esp_reset_reason()映射到MP_PWRON_RESET、MP_WDT_RESET、MP_DEEPSLEEP_RESET、MP_HARD_RESET、MP_SOFT_RESET等常量,供 Python 层诊断重启原因。
3. Python 层错误处理约定
3.1 启动阶段容错(_boot.py)
esp32s3/firmware/boards/labplus_Ledong_v2/modules/_boot.py 展示了典型的启动容错模式:
挂载文件系统失败时捕获
OSError,回退到inisetup.setup()重建 VFS。获取机器型号、MAC 地址等操作均用
try/except包裹,失败时打印Unknown machine/Unknown mac而非中断启动。上电后立即关闭 RGB LED 防止随机灯亮,属于“先初始化再尝试业务”的容错策略。
3.2 传感器/I2C 设备封装层的重试 + 明确异常
esp32s3/firmware/boards/labplus_Ledong_v2/modules/mpython.py 中磁力计/加速度计相关代码呈现固定模式:
每个 I2C 读/写序列外层套
retry < 5的循环。内部用裸
try:捕获所有异常(包括 I2C 底层抛出的OSError),失败则retry += 1。重试耗尽后
raise Exception("i2c read/write error!"),抛出一个无具体类型的通用Exception,而非OSError或自定义异常类。该模式出现在_get_raw、_get_temperature、_get_id、_judge_id等多个方法中。
3.3 BLE 自定义异常
esp32s3/firmware/boards/labplus_Ledong_v2/modules/educore/mpython_ble/advertising/__init__.py 定义了 class BLEError(Exception):,是仓库中唯一观察到的自定义异常类,用于 BLE 子系统。
3.4 示例代码中的网络错误处理
docs/examples/network/ 下的示例(http_server.py、tcpClient.py、udp_client.py、AnalogClock.py、DigitalClock.py 等)普遍采用 try: ... except OSError: 的模式捕获网络 I/O 错误,体现教程代码对 OSError 作为网络错误的约定。
4. 架构与分层约定
层级 |
位置 |
错误方式 |
说明 |
|---|---|---|---|
硬件驱动层(C) |
|
|
严格遵循 MicroPython 异常体系,错误信息通过 |
系统接口层(C) |
|
|
暴露 |
板级 Python 模块 |
|
|
对底层 I2C 做重试包装,但顶层仍抛通用 |
启动脚本 |
|
|
保证启动流程健壮,失败时降级 |
用户示例 |
|
|
教学示例统一捕获 |
5. 约束与规范(从代码行为归纳)
C 层禁止返回错误码给 Python:所有底层 I2C/PIN 操作失败都通过
mp_raise_*立即转为 Python 异常,调用方无需检查返回值。I2C 错误一律映射为
OSError:machine_i2c_extmod.c中所有负返回值统一经mp_raise_OSError(-ret)转换,使 Python 层可用except OSError统一处理。参数校验错误使用
ValueError:无效引脚、非法频率、非法唤醒值等均抛ValueError,便于区分“参数错误”和“运行时 I/O 错误”。启动阶段必须容忍异常:
_boot.py对所有可能失败的初始化步骤加try/except,确保即使某项服务不可用也能继续启动。传感器封装层采用“重试 + 通用 Exception”模式:
mpython.py中 I2C 访问失败最多重试 5 次,之后抛出无类型信息的Exception("i2c read/write error!")——这是一种简化设计,未定义专用异常类型。重启原因通过常量暴露:
modmachine.c将 ESP-IDF 重启原因映射为MP_PWRON_RESET、MP_WDT_RESET、MP_DEEPSLEEP_RESET、MP_HARD_RESET、MP_SOFT_RESET五个整数常量,供 Python 层machine.reset_cause()查询。BLE 子系统有独立异常命名空间:
advertising/__init__.py中BLEError是唯一自定义异常类,表明 BLE 模块有意隔离其错误域。
6. 关键文件
esp32s3/firmware/builtins/machine_i2c_extmod.c— I2C 协议层错误统一出口esp32s3/firmware/builtins/machine_i2c.c— I2C 实例化参数校验esp32s3/firmware/builtins/machine_pin.c— GPIO 引脚与唤醒配置错误firmware/port/builtins/modmachine.c— 系统重启、睡眠、频率等错误与重启原因esp32s3/firmware/boards/labplus_Ledong_v2/modules/_boot.py— 启动容错模板esp32s3/firmware/boards/labplus_Ledong_v2/modules/mpython.py— 传感器 I2C 重试与通用 Exception 模式esp32s3/firmware/boards/labplus_Ledong_v2/modules/educore/mpython_ble/advertising/__init__.py— BLE 自定义异常BLEErrordocs/examples/network/http_server.py、tcpClient.py、udp_client.py、AnalogClock.py、DigitalClock.py— 示例层try/except OSError惯例