# 双线汽车接口 (TWAI)

[English]

本编程指南包含以下部分：

## 概述

双线汽车接口 (TWAI) 是一种适用于汽车和工业应用的实时串行通信协议。它兼容 ISO11898-1 经典帧，因此可以支持标准帧格式（11 位 ID）和扩展帧格式（29 位 ID）。ESP32-H2 包含 1 个 TWAI 控制器，经配置可以在 TWAI 总线上使用外部收发器通信。

警告

TWAI 控制器不兼容 ISO11898-1 FD 格式帧，并会将这些帧解析为错误。

## TWAI 协议概述

TWAI 是一种多主机、多播、异步、串行通信协议，该协议还支持错误检测和通报，并具有内置报文优先级。

多主机： 总线上的任何节点都可以发起报文传输。

多播： 节点传输报文时，总线上的所有节点都会接收该报文（即广播），确保所有节点数据一致。但通过接收过滤，某些节点可以选择性地接收报文（多播）。

异步： 总线不包含时钟信号。总线上的所有节点以相同的位速率运行，并使用在总线上传输位的边沿进行同步。

错误检测和通报： 每个节点不断监视总线。节点检测到错误时，通过传输错误帧通报检测到的错误。其他节点会接收错误帧，并传输自己的错误帧作为回应，这样一来检测的错误即可传播到总线上的所有节点。

报文优先级： 每个报文包含唯一的 ID 字段。如果两个或多个节点尝试同时传输，ID 小的节点将获得总线的控制权，而其他节点将自动转为接收器，确保无论何时最多只有一个发射器。

### TWAI 报文

TWAI 报文分为数据帧和远程帧。数据帧用于向其他节点传递数据载荷，远程帧用于请求其他节点的数据帧，其他节点可以选择性地用数据帧响应。数据帧和远程帧有两种帧格式，称为 扩展帧 和 标准帧，分别包含了 29 位 ID 和 11 位 ID。TWAI 报文包括以下字段：

> - 29 位或 11 位的 ID：确定报文优先级，值越小优先级越高。

> - 0 到 8 之间的数据长度代码 (DLC)：以字节为单位，表示数据帧的数据载荷大小，或者远程帧请求的数据量。

> - 数据帧数据，最多为 8 个字节，应与 DLC 匹配。

### 错误状态和计数器

TWAI 协议具备“故障隔离”功能，它可以使持续存在错误的节点最终自行断开总线。该功能通过要求每个节点维护两个内部错误计数器实现，这两个计数器分别称为 发送错误计数器 (TEC)**和 **接收错误计数器 (REC)。根据一组规则，这两个错误计数器在发生错误时递增，在报文发送/接收成功时递减。计数器值决定节点的 错误状态，即 主动错误、被动错误 和 离线。

主动错误: 当 TEC 和 REC 都小于 128 时，节点处于主动错误状态，表示节点正常运行。主动错误节点可以参与总线通信，并会自动通过总线发送 主动错误标志，主动报告检测到的错误。

被动错误: 当 TEC 或 REC 中的一个大于或等于 128 时，节点处于被动错误状态。被动错误的节点仍可以参与总线通信，但在检测到错误时，只能发送一次 被动错误标志。

离线: 当 TEC 大于或等于 256 时，节点进入离线状态。离线的节点无法对总线产生任何影响，相当于断开连接，进而从总线自行清除。节点将保持离线状态，直到触发离线恢复。

## 信号线和收发器

TWAI 控制器不含集成收发器。因此，要将 TWAI 控制器连接到 TWAI 总线，需要外部收发器。所使用的外部收发器类型应根据应用的物理层规范而定。例如，使用 SN65HVD23x 收发器以兼容 ISO 11898-2。

TWAI 控制器的接口由四条信号线组成，分别为 TX、RX、BUS-OFF 和 CLKOUT。这四条信号线可以通过 GPIO 矩阵连接到 ESP32-H2 的 GPIO 管脚上。

TWAI控制器的信号线

TX 和 RX: TX 和 RX 信号线用于与外部收发器通信。这两条信号线将显性位表示/解析为低逻辑电平 (0 V)，将隐性位表示/解析为高逻辑电平 (3.3 V)。

BUS-OFF: BUS-OFF 信号线是 可选 的，在 TWAI 控制器进入离线状态时为低逻辑电平 (0 V)。否则，BUS-OFF 信号线将设置为高逻辑电平 (3.3 V)。

CLKOUT: CLKOUT 信号线是 可选 的，会输出控制器源时钟的分频时钟。

备注

外部收发器 必须在内部连接 TX 与 RX，以便观察 TX 信号线上的逻辑电平变化。如果没有内部回环，TWAI 控制器将会将两个信号线上的逻辑电平差异解析为仲裁丢失或位错误。

## API 命名规范

备注

TWAI 驱动程序提供了两套 API。其中一套是无句柄的，广泛适用于 IDF v5.2 之前的版本，但仅支持单个 TWAI 硬件控制器；另一套是带句柄的，其函数名称通常以 "v2" 为后缀，并支持任意数量的 TWAI 控制器。这两套 API 可以同时使用，但建议在新项目中使用 "v2" 版本的 API。

## 配置 TWAI 驱动

本节描述了如何配置 TWAI 驱动。

### 操作模式

TWAI 驱动支持以下操作模式：

正常模式： 正常模式支持 TWAI 控制器参与总线活动，如传输和接收报文/错误帧。发送报文时需要来自另一个节点的应答。

无应答模式： 无应答模式与正常模式类似，但不需要接收方发送应答信号，即使没有应答信号也会视为成功传输。这种模式在 TWAI 控制器（如传输回环）自测时非常有用。

只听模式： 此模式防止 TWAI 控制器干扰总线，因此会禁用报文/应答信号/错误帧的传输。但 TWAI 控制器仍然能够接收报文，只是不会应答。这种模式适用于总线监视应用。

### 报警

TWAI 驱动程序包含报警功能，可以对应用层发起特定 TWAI 控制器或 TWAI 总线事件通知。在安装 TWAI 驱动程序时，可以选择启用报警，也可以在运行时通过调用 `twai_reconfigure_alerts()` 重新配置。随后，应用程序可以通过调用 `twai_read_alerts()` 等待任何已启用的报警发生。TWAI 驱动程序支持以下报警：

TWAI Driver Alerts
报警标志 | 描述
--- | ---
`TWAI_ALERT_TX_IDLE` | 队列中无待传输报文
`TWAI_ALERT_TX_SUCCESS` | 上一次传输成功
`TWAI_ALERT_RX_DATA` | 收到一帧数据并添加到 RX 队列
`TWAI_ALERT_BELOW_ERR_WARN` | 两个错误计数器都低于错误报警限制
`TWAI_ALERT_ERR_ACTIVE` | TWAI 控制器已进入主动错误状态
`TWAI_ALERT_RECOVERY_IN_PROGRESS` | TWAI 控制器正在进行离线恢复
`TWAI_ALERT_BUS_RECOVERED` | TWAI 控制器已成功完成离线恢复
`TWAI_ALERT_ARB_LOST` | 上一次传输丢失仲裁
`TWAI_ALERT_ABOVE_ERR_WARN` | 有错误计数器超过了错误报警限制
`TWAI_ALERT_BUS_ERROR` | 总线上发生了（位、填充、CRC、格式、ACK）错误
`TWAI_ALERT_TX_FAILED` | 上一次传输失败
`TWAI_ALERT_RX_QUEUE_FULL` | RX 队列已满，接收到的帧丢失
`TWAI_ALERT_ERR_PASS` | TWAI 控制器已进入被动错误状态
`TWAI_ALERT_BUS_OFF` | 离线条件已触发，TWAI 控制器无法干扰总线

备注

TWAI 控制器的 错误报警限制 用于在被动错误状态之前，预先提醒应用程序发生了总线错误。TWAI 驱动程序将 错误报警限制 默认设置为 96。当 TEC 或 REC 大于或等于错误报警限制时，将引发报警 `TWAI_ALERT_ABOVE_ERR_WARN`。当 TEC 和 REC 都返回到小于 96 的值时，将引发报警 `TWAI_ALERT_BELOW_ERR_WARN`。

备注

启用错误报警时，可以使用 `TWAI_ALERT_AND_LOG` 标志，让 TWAI 驱动程序把所有报警都记录到 UART。但是，如果启用了 CONFIG_TWAI_ISR_IN_IRAM 选项，则会禁用报警记录和 `TWAI_ALERT_AND_LOG`。请参阅 将 ISR 存入 IRAM。

备注

`TWAI_ALERT_ALL` 和 `TWAI_ALERT_NONE` 宏也可在配置或重新配置期间，启用或禁用所有报警。

### 位时序

可以使用结构体 `twai_timing_config_t` 配置 TWAI 驱动程序运行的位速率，每个位的周期由多个 时间定额 组成，TWAI 控制器源时钟的预分频时钟确定 时间定额 的周期。单个位按顺序包含以下部分：

> 1. 同步段 由一个时间定额组成

> 2. 时序段 1 在采样点之前由 1 到 16 个时间定额组成

> 3. 时序段 2 在采样点之后由 1 到 8 个时间定额组成

波特率分频器 (BRP) 通过对 TWAI 控制器的源时钟分频，确定每个时间定额的周期。在 ESP32-H2 上，`brp` 可以是 从 2 到 32768 的任何偶数。也可以将 `twai_timing_config_t::quanta_resolution_hz` 设置为非零值，决定各时间定额的分辨率。此时，驱动程序即可计算底层 `brp` 值。此方法适用于需要设置不同的时钟源，但希望位速率保持不变的情况。

TWAI 控制器支持的时钟源请参阅 `twai_clock_source_t`，可以在 `twai_timing_config_t::clk_src` 中指定时钟源。

BRP = 8、时钟源频率为 80 MHz 时，位时序配置为 500 Kbit/s

数据位的采样点位于时序段 1 和时序段 2 的交汇处，启用 三重采样 会导致每个位采样 3 个时间定额，而不是 1 个，额外的采样点位于时序段 1 尾部。

同步跳变宽度 (SJW) 用于确定单个位时间可以为了同步而延长/缩短的最大时间定额数，`sjw` 可以在 1 到 4 之间。

备注

`brp`、`tseg_1`、`tseg_2` 和 `sjw` 的不同组合可以实现相同位速率。用户应考虑 传播延迟、节点信息处理时间和相位误差 等因素，根据总线的物理特性进行调整。

常用的位速率时序可以使用 初始化宏。以下是 TWAI 驱动程序提供的一些初始化宏。

- `TWAI_TIMING_CONFIG_1MBITS`

- `TWAI_TIMING_CONFIG_800KBITS`

- `TWAI_TIMING_CONFIG_500KBITS`

- `TWAI_TIMING_CONFIG_250KBITS`

- `TWAI_TIMING_CONFIG_125KBITS`

- `TWAI_TIMING_CONFIG_100KBITS`

- `TWAI_TIMING_CONFIG_50KBITS`

- `TWAI_TIMING_CONFIG_25KBITS`

- `TWAI_TIMING_CONFIG_20KBITS`

- `TWAI_TIMING_CONFIG_16KBITS`

- `TWAI_TIMING_CONFIG_12_5KBITS`

- `TWAI_TIMING_CONFIG_10KBITS`

- `TWAI_TIMING_CONFIG_5KBITS`

- `TWAI_TIMING_CONFIG_1KBITS`

### 接收过滤器

TWAI 控制器内置硬件接收过滤器，可以过滤特定 ID 的报文。过滤掉报文的节点 不会接收到该报文，但仍会应答。接收过滤器通过过滤掉总线上与节点无关的报文，使节点更加高效。接收过滤器使用在 `twai_filter_config_t` 中的两个 32 位值配置，分别称为 接收码 和 接收掩码。

接收码 指定报文的 ID、RTR 和数据字节必须匹配的位序列，使报文可以由 TWAI 控制器接收。接收掩码 是一个位序列，指定接受码中可以忽略的位，从而实现用单个接收码接受不同 ID 的报文。

接收过滤器可以在 单过滤器模式或双过滤器模式 下使用。单过滤器模式使用接收代码和掩码定义一个过滤器，支持筛选标准帧的前两个数据字节，或扩展帧的 29 位 ID 的全部内容。以下图示说明了在单过滤器模式下解析 32 位接收代码和掩码的方式。注意：黄色和蓝色字段分别表示标准和扩展帧格式。

单过滤器模式的位布局（右侧为最高有效位）

双过滤器模式 使用接收代码和掩码定义两个单独的过滤器，支持接收更多 ID，但不支持筛选扩展 ID 的全部 29 位。以下图示说明了在 双过滤器模式 下解析 32 位接收代码和掩码的方式。注意：黄色和蓝色字段分别表示标准和扩展帧格式。

双过滤器模式的位布局（右侧为最高有效位）

### 禁用 TX 队列

可以将 `twai_general_config_t` 结构体的 `tx_queue_len` 成员设置为 `0`，在配置期间禁用 TX 队列。使用 TWAI 驱动程序时，禁用 TX 队列可以为不需要报文传输的应用程序节省一小部分内存。

### 将 ISR 存入 IRAM

TWAI 驱动程序的 ISR（中断服务程序）可以存入 IRAM，这样可以在禁用 cache 时运行 ISR。长时间禁用 cache 时（例如 SPI flash 写操作、OTA 更新等），可能需要将 ISR 存入 IRAM，才能确保 TWAI 驱动程序的功能。禁用 cache 时，ISR 继续执行以下操作：

- 从 RX buffer 读取接收到的报文，并将它们存入驱动程序的 RX 队列。

- 从驱动程序的 TX 队列中加载待传输的报文，并将它们写入 TX buffer。

将 TWAI 驱动程序的 ISR 存入 IRAM，必须执行以下操作：

- 使用 `idf.py menuconfig` 启用 CONFIG_TWAI_ISR_IN_IRAM 选项。

- 调用 `twai_driver_install()` 时，`twai_general_config_t` 的成员 `intr_flags` 应设置为 `ESP_INTR_FLAG_IRAM`。

备注

启用 CONFIG_TWAI_ISR_IN_IRAM 选项时，TWAI 驱动程序将不再记录报警，即 `TWAI_ALERT_AND_LOG` 标志失效。

## 驱动程序操作

TWAI 驱动程序经设计，具有明确定义的状态和严格的规则，规定了触发状态转换的函数或条件。下图展示了各种状态及其转换。

TWAI 驱动程序状态转换图（请参阅下表）

标签 | 转换 | 行为/条件
--- | --- | ---
A | 未安装 -> 已停止 | `twai_driver_install()`
B | 已停止 -> 未安装 | `twai_driver_uninstall()`
C | 已停止 -> 运行中 | `twai_start()`
D | 运行中 -> 已停止 | `twai_stop()`
E | 运行中 -> 离线 | 传输错误计数 >= 256
F | 离线 -> 未安装 | `twai_driver_uninstall()`
G | 离线 -> 恢复中 | `twai_initiate_recovery()`
H | 恢复中 -> 已停止 | 11 个连续的隐性位出现了 128 次

### 驱动程序状态

未安装：在此状态下，不会为驱动程序分配任何内存，且 TWAI 控制器处于掉电状态。

已停止：在此状态下，TWAI 控制器已上电，且 TWAI 驱动程序已安装。但 TWAI 控制器无法参与任何总线活动，如传输、接收或确认报文。

运行中：在此状态下，TWAI 控制器能够参与总线活动，因此可以传输/接收/应答报文。此外，TWAI 控制器能够在检测到总线上的错误时传输错误帧。

离线：TWAI 控制器的传输错误计数器计数大于或等于 256 时，将自动进入离线状态。离线状态表示总线或 TWAI 控制器上发生严重错误。在离线状态下，TWAI 控制器无法参与任何总线活动。退出离线状态前，TWAI 控制器必须进行离线恢复。

恢复中：TWAI 控制器进行离线恢复时，将进入恢复中状态。在此状态下，TWAI 控制器/TWAI 驱动程序将保持状态，直到在总线上检测到 128 次连续 11 个隐性位。

### 报文字段和标志

TWAI 驱动程序通过 `twai_message_t` 结构体的不同位字段成员区分不同类型的报文。这些位字段成员决定了报文是标准格式还是扩展格式、是否是远程帧以及在传输时要使用的传输类型。

这些位字段成员还可以使用 `twai_message_t` 的 `flags` 成员以及以下报文标志切换：

报文标志 | 描述
--- | ---
`TWAI_MSG_FLAG_EXTD` | 报文采用扩展帧格式（29 位 ID）
`TWAI_MSG_FLAG_RTR` | 报文为远程帧（远程传输请求）
`TWAI_MSG_FLAG_SS` | 使用单次发送传输报文，即报文不会在出现错误或仲裁丢失时重新传输（不用于接收报文）
`TWAI_MSG_FLAG_SELF` | 使用自接收请求传输报文，即传输的报文将由同一节点接收（不用于接收报文）
`TWAI_MSG_FLAG_DLC_NON_COMP` | 报文的数据长度代码大于 8，不符合 TWAI 的规定
`TWAI_MSG_FLAG_NONE` | 清除所有位字段，等同于标准帧格式（11 位 ID）数据帧

## 示例

### 配置及安装

以下代码片段展示了如何使用各种配置结构体、初始化宏、`twai_driver_install()` 函数和 `twai_start()` 函数，来配置、安装和启动 TWAI 驱动程序。

    #include "driver/gpio.h"
    #include "driver/twai.h"

    void app_main()
    {
        // 使用初始化宏初始化配置结构体
        twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_21, GPIO_NUM_22, TWAI_MODE_NORMAL);
        twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
        twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

        // 安装 TWAI 驱动程序
        if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
            printf("Driver installed\n");
        } else {
            printf("Failed to install driver\n");
            return;
        }

        // 启动 TWAI 驱动程序
        if (twai_start() == ESP_OK) {
            printf("Driver started\n");
        } else {
            printf("Failed to start driver\n");
            return;
        }

        ...

    }

初始化宏并非强制的，每个配置结构体都可以手动完成。

### 安装多个 TWAI 实例

注意： ESP32-H2 包含 1 个 TWAI 控制器，因此可创建 1 个 TWAI 实例。

以下代码片段演示了如何使用 `twai_driver_install_v2()` 函数来安装多个 TWAI 实例。

    #include "driver/gpio.h"
    #include "driver/twai.h"

    void app_main()
    {
        twai_handle_t twai_bus_0;
        twai_handle_t twai_bus_1;
        // 使用宏初始化器初始化配置结构体
        twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_0, GPIO_NUM_1, TWAI_MODE_NORMAL);
        twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
        twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

        // 安装 TWAI 总线 0 的驱动程序
        g_config.controller_id = 0;
        if (twai_driver_install_v2(&g_config, &t_config, &f_config, &twai_bus_0) == ESP_OK) {
            printf("Driver installed\n");
        } else {
            printf("Failed to install driver\n");
            return;
        }
        // 启动 TWAI 驱动程序
        if (twai_start_v2(twai_bus_0) == ESP_OK) {
            printf("Driver started\n");
        } else {
            printf("Failed to start driver\n");
            return;
        }

        // 安装 TWAI 总线 1 的驱动程序
        g_config.controller_id = 1;
        g_config.tx_io = GPIO_NUM_2;
        g_config.rx_io = GPIO_NUM_3;
        if (twai_driver_install_v2(&g_config, &t_config, &f_config, &twai_bus_1) == ESP_OK) {
            printf("Driver installed\n");
        } else {
            printf("Failed to install driver\n");
            return;
        }
        // 启动 TWAI 驱动程序
        if (twai_start_v2(twai_bus_1) == ESP_OK) {
            printf("Driver started\n");
        } else {
            printf("Failed to start driver\n");
            return;
        }

        // 其他驱动程序操作也必须使用 _v2 版本的 API
        ...

    }

### 报文传输

以下代码片段展示了如何使用 `twai_message_t` 类型和 `twai_transmit()` 函数传输报文。

    #include "driver/twai.h"

    ...

    // 配置要传输的报文
    twai_message_t message = {
        // 设置报文类型及格式
        .extd = 1,              // 标准格式或是扩展格式
        .rtr = 0,               // 数据帧或是远程传输请求帧
        .ss = 0,                // 报文是否为单次发送（即，在报错时不重复发送）
        .self = 0,              // 报文是否为自收发（回环）
        .dlc_non_comp = 0,      // 数据长度代码小于 8
        // 报文 ID 及有效载荷
        .identifier = 0xAAAA,
        .data_length_code = 4,
        .data = {0, 1, 2, 3},
    };

    // 报文排队等待传输
    if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        printf("Message queued for transmission\n");
    } else {
        printf("Failed to queue message for transmission\n");
    }

### 报文接收

以下代码片段展示了如何使用 `twai_message_t` 类型和 `twai_receive()` 函数接收报文。

    #include "driver/twai.h"

    ...

    // 等待报文接收
    twai_message_t message;
    if (twai_receive(&message, pdMS_TO_TICKS(10000)) == ESP_OK) {
        printf("Message received\n");
    } else {
        printf("Failed to receive message\n");
        return;
    }

    // 处理接收到的报文
    if (message.extd) {
        printf("Message is in Extended Format\n");
    } else {
        printf("Message is in Standard Format\n");
    }
    printf("ID is %d\n", message.identifier);
    if (!(message.rtr)) {
        for (int i = 0; i < message.data_length_code; i++) {
            printf("Data byte %d = %d\n", i, message.data[i]);
        }
    }

### 重新配置并读取报警

以下代码片段展示了如何使用 `twai_reconfigure_alerts()` 和 `twai_read_alerts()` 函数重新配置和读取 TWAI 驱动程序的报警。

    #include "driver/twai.h"

    ...

    // 重新配置报警，检测被动错误和离线状态
    uint32_t alerts_to_enable = TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_OFF;
    if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
        printf("Alerts reconfigured\n");
    } else {
        printf("Failed to reconfigure alerts");
    }

    // 阻塞直到发生报警
    uint32_t alerts_triggered;
    twai_read_alerts(&alerts_triggered, portMAX_DELAY);

### 停止和卸载

以下代码片段展示了如何使用 `twai_stop()` 和 `twai_driver_uninstall()` 函数停止和卸载 TWAI 驱动程序。

    #include "driver/twai.h"

    ...

    // 停止 TWAI 驱动程序
    if (twai_stop() == ESP_OK) {
        printf("Driver stopped\n");
    } else {
        printf("Failed to stop driver\n");
        return;
    }

    // 卸载 TWAI 驱动程序
    if (twai_driver_uninstall() == ESP_OK) {
        printf("Driver uninstalled\n");
    } else {
        printf("Failed to uninstall driver\n");
        return;
    }

### 配置多个 ID 过滤器

`twai_filter_config_t` 中的接收掩码可以配置，使单过滤器接收两个或多个 ID。为了使特定过滤器接受多个 ID，必须在接收掩码中设置不同 ID 的冲突位。接收代码可以设置为这些 ID 中的任何一个。

以下示例展示了如何计算多个 ID 的接收掩码：

    ID1 =  11'b101 1010 0000
    ID2 =  11'b101 1010 0001
    ID3 =  11'b101 1010 0100
    ID4 =  11'b101 1010 1000
    // 接收掩码
    MASK = 11'b000 0000 1101

### 应用示例

网络示例： peripherals/twai/twai_network 演示了如何通过 TWAI 驱动程序 API 在两个 ESP32-H2 之间进行通信。其中一个 TWAI 节点为网络主节点，负责启动和终止与另一个网络从节点之间的数据传输。

报警和恢复示例： peripherals/twai/twai_alert_and_recovery 演示了如何在 ESP32-H2 上使用 TWAI 驱动程序的报警和离线恢复 API。通过初始化驱动程序，该示例创建消息传输和警报处理任务，触发比特错误进入 Bus-Off 离线状态，报警检测离线状态，并触发 Bus-Off 离线恢复过程。

自测示例： peripherals/twai/twai_self_test 演示了节点如何使用 TWAI 驱动程序的无应答模式和自接收请求，向自身传输 TWAI 消息。此示例可用于测试目标芯片与外部收发器之间的连接是否正常。

### 睡眠保留

ESP32-H2 支持在进入 Light Sleep 之前保留 TWAI 寄存器中的内容，并在唤醒后恢复。即程序不需要在 Light Sleep 唤醒后重新配置 TWAI

该特性可以通过置位配置中的 `twai_general_config_t::sleep_allow_pd` 标志位启用。启用后驱动允许系统在 Light Sleep 时对 TWAI 掉电，同时保存寄存器配置。它可以帮助降低轻度睡眠时的功耗，但需要花费一些额外的存储来保存寄存器的配置。

## API 参考

### Header File

- components/hal/include/hal/twai_types.h

- This header file can be included with:

  >     #include "hal/twai_types.h"

### Structures

struct twai_message_t

  Structure to store a TWAI message.

  备注

  The flags member is deprecated

  Public Members

  uint32_t extd

    Extended Frame Format (29bit ID)

  uint32_t rtr

    Message is a Remote Frame

  uint32_t ss

    Transmit as a Single Shot Transmission. Unused for received.

  uint32_t self

    Transmit as a Self Reception Request. Unused for received.

  uint32_t dlc_non_comp

    Message's Data length code is larger than 8. This will break compliance with ISO 11898-1

  uint32_t reserved

    Reserved bits

  uint32_t flags

    Deprecated: Alternate way to set bits using message flags

  uint32_t identifier

    11 or 29 bit identifier

  uint8_t data_length_code

    Data length code

  uint8_t data[TWAI_FRAME_MAX_DLC]

    Data bytes (not relevant in RTR frame)

struct twai_timing_config_t

  Structure for bit timing configuration of the TWAI driver.

  备注

  Macro initializers are available for this structure

  Public Members

  twai_clock_source_t clk_src

    Clock source, set to 0 or TWAI_CLK_SRC_DEFAULT if you want a default clock source

  uint32_t quanta_resolution_hz

    The resolution of one timing quanta, in Hz. Note: the value of `brp` will reflected by this field if it's non-zero, otherwise, `brp` needs to be set manually

  uint32_t brp

    Baudrate prescale (i.e., clock divider). Any even number from 2 to 128 for ESP32, 2 to 32768 for non-ESP32 chip. Note: For ESP32 ECO 2 or later, multiples of 4 from 132 to 256 are also supported

  uint8_t tseg_1

    Timing segment 1 (Number of time quanta, between 1 to 16)

  uint8_t tseg_2

    Timing segment 2 (Number of time quanta, 1 to 8)

  uint8_t sjw

    Synchronization Jump Width (Max time quanta jump for synchronize from 1 to 4)

  bool triple_sampling

    Enables triple sampling when the TWAI controller samples a bit

struct twai_filter_config_t

  Structure for acceptance filter configuration of the TWAI driver (see documentation)

  备注

  Macro initializers are available for this structure

  Public Members

  uint32_t acceptance_code

    32-bit acceptance code

  uint32_t acceptance_mask

    32-bit acceptance mask

  bool single_filter

    Use Single Filter Mode (see documentation)

### Macros

TWAI_EXTD_ID_MASK

  TWAI Constants.

  Bit mask for 29 bit Extended Frame Format ID

TWAI_STD_ID_MASK

  Bit mask for 11 bit Standard Frame Format ID

TWAI_FRAME_MAX_DLC

  Max data bytes allowed in TWAI

TWAI_FRAME_EXTD_ID_LEN_BYTES

  EFF ID requires 4 bytes (29bit)

TWAI_FRAME_STD_ID_LEN_BYTES

  SFF ID requires 2 bytes (11bit)

TWAI_ERR_PASS_THRESH

  Error counter threshold for error passive

### Type Definitions

typedef soc_periph_twai_clk_src_t twai_clock_source_t

  RMT group clock source.

  备注

  User should select the clock source based on the power and resolution requirement

### Enumerations

enum twai_mode_t

  TWAI Controller operating modes.

  Values:

  enumerator TWAI_MODE_NORMAL

    Normal operating mode where TWAI controller can send/receive/acknowledge messages

  enumerator TWAI_MODE_NO_ACK

    Transmission does not require acknowledgment. Use this mode for self testing

  enumerator TWAI_MODE_LISTEN_ONLY

    The TWAI controller will not influence the bus (No transmissions or acknowledgments) but can receive messages

### Header File

- components/driver/twai/include/driver/twai.h

- This header file can be included with:

  >     #include "driver/twai.h"

- This header file is a part of the API provided by the `driver` component. To declare that your component depends on `driver`, add the following to your CMakeLists.txt:

  >     REQUIRES driver

  > or

  >     PRIV_REQUIRES driver

### Functions

esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config)

  Install TWAI driver.

  This function installs the TWAI driver using three configuration structures. The required memory is allocated and the TWAI driver is placed in the stopped state after running this function.

  备注

  Macro initializers are available for the configuration structures (see documentation)

  备注

  To reinstall the TWAI driver, call twai_driver_uninstall() first

  参数:

    - g_config -- [in] General configuration structure

    - t_config -- [in] Timing configuration structure

    - f_config -- [in] Filter configuration structure

  返回:

    - ESP_OK: Successfully installed TWAI driver

    - ESP_ERR_INVALID_ARG: Arguments are invalid, e.g. invalid clock source, invalid quanta resolution

    - ESP_ERR_NO_MEM: Insufficient memory

    - ESP_ERR_INVALID_STATE: Driver is already installed

esp_err_t twai_driver_install_v2(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config, twai_handle_t *ret_twai)

  Install TWAI driver and return a handle.

  备注

  This is an advanced version of `twai_driver_install` that can return a driver handle, so that it allows you to install multiple TWAI drivers. Don't forget to set the proper controller_id in the `twai_general_config_t` Please refer to the documentation of `twai_driver_install` for more details.

  参数:

    - g_config -- [in] General configuration structure

    - t_config -- [in] Timing configuration structure

    - f_config -- [in] Filter configuration structure

    - ret_twai -- [out] Pointer to a new created TWAI handle

  返回:

    - ESP_OK: Successfully installed TWAI driver

    - ESP_ERR_INVALID_ARG: Arguments are invalid, e.g. invalid clock source, invalid quanta resolution, invalid controller ID

    - ESP_ERR_NO_MEM: Insufficient memory

    - ESP_ERR_INVALID_STATE: Driver is already installed

esp_err_t twai_driver_uninstall(void)

  Uninstall the TWAI driver.

  This function uninstalls the TWAI driver, freeing the memory utilized by the driver. This function can only be called when the driver is in the stopped state or the bus-off state.

  警告

  The application must ensure that no tasks are blocked on TX/RX queues or alerts when this function is called.

  返回:

    - ESP_OK: Successfully uninstalled TWAI driver

    - ESP_ERR_INVALID_STATE: Driver is not in stopped/bus-off state, or is not installed

esp_err_t twai_driver_uninstall_v2(twai_handle_t handle)

  Uninstall the TWAI driver with a given handle.

  备注

  This is an advanced version of `twai_driver_uninstall` that can uninstall a TWAI driver with a given handle. Please refer to the documentation of `twai_driver_uninstall` for more details.

  参数:

    handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

  返回:

    - ESP_OK: Successfully uninstalled TWAI driver

    - ESP_ERR_INVALID_STATE: Driver is not in stopped/bus-off state, or is not installed

esp_err_t twai_start(void)

  Start the TWAI driver.

  This function starts the TWAI driver, putting the TWAI driver into the running state. This allows the TWAI driver to participate in TWAI bus activities such as transmitting/receiving messages. The TX and RX queue are reset in this function, clearing any messages that are unread or pending transmission. This function can only be called when the TWAI driver is in the stopped state.

  返回:

    - ESP_OK: TWAI driver is now running

    - ESP_ERR_INVALID_STATE: Driver is not in stopped state, or is not installed

esp_err_t twai_start_v2(twai_handle_t handle)

  Start the TWAI driver with a given handle.

  备注

  This is an advanced version of `twai_start` that can start a TWAI driver with a given handle. Please refer to the documentation of `twai_start` for more details.

  参数:

    handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

  返回:

    - ESP_OK: TWAI driver is now running

    - ESP_ERR_INVALID_STATE: Driver is not in stopped state, or is not installed

esp_err_t twai_stop(void)

  Stop the TWAI driver.

  This function stops the TWAI driver, preventing any further message from being transmitted or received until twai_start() is called. Any messages in the TX queue are cleared. Any messages in the RX queue should be read by the application after this function is called. This function can only be called when the TWAI driver is in the running state.

  警告

  A message currently being transmitted/received on the TWAI bus will be ceased immediately. This may lead to other TWAI nodes interpreting the unfinished message as an error.

  返回:

    - ESP_OK: TWAI driver is now Stopped

    - ESP_ERR_INVALID_STATE: Driver is not in running state, or is not installed

esp_err_t twai_stop_v2(twai_handle_t handle)

  Stop the TWAI driver with a given handle.

  备注

  This is an advanced version of `twai_stop` that can stop a TWAI driver with a given handle. Please refer to the documentation of `twai_stop` for more details.

  参数:

    handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

  返回:

    - ESP_OK: TWAI driver is now Stopped

    - ESP_ERR_INVALID_STATE: Driver is not in running state, or is not installed

esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait)

  Transmit a TWAI message.

  This function queues a TWAI message for transmission. Transmission will start immediately if no other messages are queued for transmission. If the TX queue is full, this function will block until more space becomes available or until it times out. If the TX queue is disabled (TX queue length = 0 in configuration), this function will return immediately if another message is undergoing transmission. This function can only be called when the TWAI driver is in the running state and cannot be called under Listen Only Mode.

  备注

  This function does not guarantee that the transmission is successful. The TX_SUCCESS/TX_FAILED alert can be enabled to alert the application upon the success/failure of a transmission.

  备注

  The TX_IDLE alert can be used to alert the application when no other messages are awaiting transmission.

  参数:

    - message -- [in] Message to transmit

    - ticks_to_wait -- [in] Number of FreeRTOS ticks to block on the TX queue

  返回:

    - ESP_OK: Transmission successfully queued/initiated

    - ESP_ERR_INVALID_ARG: Arguments are invalid

    - ESP_ERR_TIMEOUT: Timed out waiting for space on TX queue

    - ESP_FAIL: TX queue is disabled and another message is currently transmitting

    - ESP_ERR_INVALID_STATE: TWAI driver is not in running state, or is not installed

    - ESP_ERR_NOT_SUPPORTED: Listen Only Mode does not support transmissions

esp_err_t twai_transmit_v2(twai_handle_t handle, const twai_message_t *message, TickType_t ticks_to_wait)

  Transmit a TWAI message via a given handle.

  备注

  This is an advanced version of `twai_transmit` that can transmit a TWAI message with a given handle. Please refer to the documentation of `twai_transmit` for more details.

  参数:

    - handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

    - message -- [in] Message to transmit

    - ticks_to_wait -- [in] Number of FreeRTOS ticks to block on the TX queue

  返回:

    - ESP_OK: Transmission successfully queued/initiated

    - ESP_ERR_INVALID_ARG: Arguments are invalid

    - ESP_ERR_TIMEOUT: Timed out waiting for space on TX queue

    - ESP_FAIL: TX queue is disabled and another message is currently transmitting

    - ESP_ERR_INVALID_STATE: TWAI driver is not in running state, or is not installed

    - ESP_ERR_NOT_SUPPORTED: Listen Only Mode does not support transmissions

esp_err_t twai_receive(twai_message_t *message, TickType_t ticks_to_wait)

  Receive a TWAI message.

  This function receives a message from the RX queue. The flags field of the message structure will indicate the type of message received. This function will block if there are no messages in the RX queue

  警告

  The flags field of the received message should be checked to determine if the received message contains any data bytes.

  参数:

    - message -- [out] Received message

    - ticks_to_wait -- [in] Number of FreeRTOS ticks to block on RX queue

  返回:

    - ESP_OK: Message successfully received from RX queue

    - ESP_ERR_TIMEOUT: Timed out waiting for message

    - ESP_ERR_INVALID_ARG: Arguments are invalid

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

esp_err_t twai_receive_v2(twai_handle_t handle, twai_message_t *message, TickType_t ticks_to_wait)

  Receive a TWAI message via a given handle.

  备注

  This is an advanced version of `twai_receive` that can receive a TWAI message with a given handle. Please refer to the documentation of `twai_receive` for more details.

  参数:

    - handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

    - message -- [out] Received message

    - ticks_to_wait -- [in] Number of FreeRTOS ticks to block on RX queue

  返回:

    - ESP_OK: Message successfully received from RX queue

    - ESP_ERR_TIMEOUT: Timed out waiting for message

    - ESP_ERR_INVALID_ARG: Arguments are invalid

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

esp_err_t twai_read_alerts(uint32_t *alerts, TickType_t ticks_to_wait)

  Read TWAI driver alerts.

  This function will read the alerts raised by the TWAI driver. If no alert has been issued when this function is called, this function will block until an alert occurs or until it timeouts.

  备注

  Multiple alerts can be raised simultaneously. The application should check for all alerts that have been enabled.

  参数:

    - alerts -- [out] Bit field of raised alerts (see documentation for alert flags)

    - ticks_to_wait -- [in] Number of FreeRTOS ticks to block for alert

  返回:

    - ESP_OK: Alerts read

    - ESP_ERR_TIMEOUT: Timed out waiting for alerts

    - ESP_ERR_INVALID_ARG: Arguments are invalid

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

esp_err_t twai_read_alerts_v2(twai_handle_t handle, uint32_t *alerts, TickType_t ticks_to_wait)

  Read TWAI driver alerts with a given handle.

  备注

  This is an advanced version of `twai_read_alerts` that can read TWAI driver alerts with a given handle. Please refer to the documentation of `twai_read_alerts` for more details.

  参数:

    - handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

    - alerts -- [out] Bit field of raised alerts (see documentation for alert flags)

    - ticks_to_wait -- [in] Number of FreeRTOS ticks to block for alert

  返回:

    - ESP_OK: Alerts read

    - ESP_ERR_TIMEOUT: Timed out waiting for alerts

    - ESP_ERR_INVALID_ARG: Arguments are invalid

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

esp_err_t twai_reconfigure_alerts(uint32_t alerts_enabled, uint32_t *current_alerts)

  Reconfigure which alerts are enabled.

  This function reconfigures which alerts are enabled. If there are alerts which have not been read whilst reconfiguring, this function can read those alerts.

  参数:

    - alerts_enabled -- [in] Bit field of alerts to enable (see documentation for alert flags)

    - current_alerts -- [out] Bit field of currently raised alerts. Set to NULL if unused

  返回:

    - ESP_OK: Alerts reconfigured

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

esp_err_t twai_reconfigure_alerts_v2(twai_handle_t handle, uint32_t alerts_enabled, uint32_t *current_alerts)

  Reconfigure which alerts are enabled, with a given handle.

  备注

  This is an advanced version of `twai_reconfigure_alerts` that can reconfigure which alerts are enabled with a given handle. Please refer to the documentation of `twai_reconfigure_alerts` for more details.

  参数:

    - handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

    - alerts_enabled -- [in] Bit field of alerts to enable (see documentation for alert flags)

    - current_alerts -- [out] Bit field of currently raised alerts. Set to NULL if unused

  返回:

    - ESP_OK: Alerts reconfigured

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

esp_err_t twai_initiate_recovery(void)

  Start the bus recovery process.

  This function initiates the bus recovery process when the TWAI driver is in the bus-off state. Once initiated, the TWAI driver will enter the recovering state and wait for 128 occurrences of the bus-free signal on the TWAI bus before returning to the stopped state. This function will reset the TX queue, clearing any messages pending transmission.

  备注

  The BUS_RECOVERED alert can be enabled to alert the application when the bus recovery process completes.

  返回:

    - ESP_OK: Bus recovery started

    - ESP_ERR_INVALID_STATE: TWAI driver is not in the bus-off state, or is not installed

esp_err_t twai_initiate_recovery_v2(twai_handle_t handle)

  Start the bus recovery process with a given handle.

  备注

  This is an advanced version of `twai_initiate_recovery` that can start the bus recovery process with a given handle. Please refer to the documentation of `twai_initiate_recovery` for more details.

  参数:

    handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

  返回:

    - ESP_OK: Bus recovery started

    - ESP_ERR_INVALID_STATE: TWAI driver is not in the bus-off state, or is not installed

esp_err_t twai_get_status_info(twai_status_info_t *status_info)

  Get current status information of the TWAI driver.

  参数:

    status_info -- [out] Status information

  返回:

    - ESP_OK: Status information retrieved

    - ESP_ERR_INVALID_ARG: Arguments are invalid

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

esp_err_t twai_get_status_info_v2(twai_handle_t handle, twai_status_info_t *status_info)

  Get current status information of a given TWAI driver handle.

  备注

  This is an advanced version of `twai_get_status_info` that can get current status information of a given TWAI driver handle. Please refer to the documentation of `twai_get_status_info` for more details.

  参数:

    - handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

    - status_info -- [out] Status information

  返回:

    - ESP_OK: Status information retrieved

    - ESP_ERR_INVALID_ARG: Arguments are invalid

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

esp_err_t twai_clear_transmit_queue(void)

  Clear the transmit queue.

  This function will clear the transmit queue of all messages.

  备注

  The transmit queue is automatically cleared when twai_stop() or twai_initiate_recovery() is called.

  返回:

    - ESP_OK: Transmit queue cleared

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed or TX queue is disabled

esp_err_t twai_clear_transmit_queue_v2(twai_handle_t handle)

  Clear the transmit queue of a given TWAI driver handle.

  备注

  This is an advanced version of `twai_clear_transmit_queue` that can clear the transmit queue of a given TWAI driver handle. Please refer to the documentation of `twai_clear_transmit_queue` for more details.

  参数:

    handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

  返回:

    - ESP_OK: Transmit queue cleared

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed or TX queue is disabled

esp_err_t twai_clear_receive_queue(void)

  Clear the receive queue.

  This function will clear the receive queue of all messages.

  备注

  The receive queue is automatically cleared when twai_start() is called.

  返回:

    - ESP_OK: Transmit queue cleared

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

esp_err_t twai_clear_receive_queue_v2(twai_handle_t handle)

  Clear the receive queue of a given TWAI driver handle.

  备注

  This is an advanced version of `twai_clear_receive_queue` that can clear the receive queue of a given TWAI driver handle. Please refer to the documentation of `twai_clear_receive_queue` for more details.

  参数:

    handle -- [in] TWAI driver handle returned by `twai_driver_install_v2`

  返回:

    - ESP_OK: Transmit queue cleared

    - ESP_ERR_INVALID_STATE: TWAI driver is not installed

### Structures

struct twai_general_config_t

  Structure for general configuration of the TWAI driver.

  备注

  Macro initializers are available for this structure

  Public Members

  int controller_id

    TWAI controller ID, index from 0. If you want to install TWAI driver with a non-zero controller_id, please use `twai_driver_install_v2`

  twai_mode_t mode

    Mode of TWAI controller

  gpio_num_t tx_io

    Transmit GPIO number

  gpio_num_t rx_io

    Receive GPIO number

  gpio_num_t clkout_io

    CLKOUT GPIO number (optional, set to -1 if unused)

  gpio_num_t bus_off_io

    Bus off indicator GPIO number (optional, set to -1 if unused)

  uint32_t tx_queue_len

    Number of messages TX queue can hold (set to 0 to disable TX Queue)

  uint32_t rx_queue_len

    Number of messages RX queue can hold

  uint32_t alerts_enabled

    Bit field of alerts to enable (see documentation)

  uint32_t clkout_divider

    CLKOUT divider. Can be 1 or any even number from 2 to 14 (optional, set to 0 if unused)

  int intr_flags

    Interrupt flags to set the priority of the driver's ISR. Note that to use the ESP_INTR_FLAG_IRAM, the CONFIG_TWAI_ISR_IN_IRAM option should be enabled first.

  uint32_t sleep_allow_pd

    Set to allow power down. When this flag set, the driver will backup/restore the TWAI registers before/after entering/exist sleep mode. By this approach, the system can power off TWAI's power domain. This can save power, but at the expense of more RAM being consumed.

  struct twai_general_config_t general_flags

    General flags

struct twai_status_info_t

  Structure to store status information of TWAI driver.

  Public Members

  twai_state_t state

    Current state of TWAI controller (Stopped/Running/Bus-Off/Recovery)

  uint32_t msgs_to_tx

    Number of messages queued for transmission or awaiting transmission completion

  uint32_t msgs_to_rx

    Number of messages in RX queue waiting to be read

  uint32_t tx_error_counter

    Current value of Transmit Error Counter

  uint32_t rx_error_counter

    Current value of Receive Error Counter

  uint32_t tx_failed_count

    Number of messages that failed transmissions

  uint32_t rx_missed_count

    Number of messages that were lost due to a full RX queue (or errata workaround if enabled)

  uint32_t rx_overrun_count

    Number of messages that were lost due to a RX FIFO overrun

  uint32_t arb_lost_count

    Number of instances arbitration was lost

  uint32_t bus_error_count

    Number of instances a bus error has occurred

### Macros

TWAI_IO_UNUSED

  Marks GPIO as unused in TWAI configuration

### Type Definitions

typedef struct twai_obj_t *twai_handle_t

  TWAI controller handle.

### Enumerations

enum twai_state_t

  TWAI driver states.

  Values:

  enumerator TWAI_STATE_STOPPED

    Stopped state. The TWAI controller will not participate in any TWAI bus activities

  enumerator TWAI_STATE_RUNNING

    Running state. The TWAI controller can transmit and receive messages

  enumerator TWAI_STATE_BUS_OFF

    Bus-off state. The TWAI controller cannot participate in bus activities until it has recovered

  enumerator TWAI_STATE_RECOVERING

    Recovering state. The TWAI controller is undergoing bus recovery

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。