# Lin_AutoBaud_Dma_Demo

---

## 功能描述

本示例演示如何在 **YTM32B1LE1** 平台上，基于 **UART0 + LIN Driver + GPIO 单边沿 DMA 触发 + pTMR 时间戳采样** 实现 **LIN 从机自适应波特率（Auto Baud）同步**。

该 Demo 的重点不是固定波特率下的 LIN 收发，而是展示从机如何在接收到主机 Header 后：

1. 利用 LIN 外设识别 Break；
2. 在 Break OK 后切 RX 到 GPIO，并在 **Sync start falling 到来之前**进入 falling-edge DMA 采样；
3. 连续采集 `Sync = 0x55` 的 `5` 个 falling edge 时间戳，并利用其中 `4` 个 two-bit 间隔估算当前总线波特率；
4. 在 **第 5 次 falling edge 到 Sync stop rising** 的 `1 bit` 窗口内完成 GPIO 模式切换, 同时完成 UART 波特率预配置；
5. 等到 **Sync stop rising** 才切回 UART 复用，继续接收 PID 和后续数据。

与 `Lin_AutoBaud_Interrupt_Demo` 的核心差异在于：

- Sync 的 `5` 次 falling edge 时间戳由 DMA 自动搬运，不再依赖逐次 GPIO ISR 取时；
- falling-edge 采样路径对每边沿 ISR 入口延迟的敏感性显著下降；
- 实时性压力集中在两个位置：
  - DMA 完成回调必须在 `bit7 falling -> Sync stop rising` 的 `1 bit` 窗口内完成 GPIO 模式切换；
  - 最后的 rising-edge GPIO ISR 必须在 PID 起始位到来前完成 RX 路径切回和 UART 波特率预配置。

**默认配置：**

- **通信角色**：LIN Slave（从机）
- **LIN 实例**：UART0
- **标称波特率**：`19200 bps`
- **自适应模式**：默认 `每帧自适应`，可切换为 `上电后首次成功后锁定`
- **目标自适应范围**：相对标称波特率 `±10.5%`
- **接收 PID**：`0x3C`
- **发送 PID**：`0x3D`
- **发送数据**：`55 AA 69 96 96 69 AA 55`

**功能特性：**

- **DMA 时间戳采样**：GPIO RX falling-edge 直接触发 DMA，将 `pTMR0 CH0->TCV` 连续搬运到内存数组；
- **5 点采样、4 段 two-bit 估算**：采集 `Sync start / bit1 / bit3 / bit5 / bit7` 五个 falling 时间点；
- **快速重配 UART**：基于 OSR 候选表 `{16, 8, 32, 12, 24, 20, 4}` 搜索最优 `OSR/SBR`；
- **0.5% 搜索精度目标**：用于提升 UART 分频搜索质量，不等同于总线可接受波特率范围；
- **stop rising 才切回 UART**：DMA 回调只完成预配置，最终 RX 路径交接只在 `Sync stop rising` 发生；
- **可切换自适应策略**：支持 `每帧重算` 或 `首次完整帧成功后锁定`；
- **单文件移植**：核心逻辑集中在 `app/main.c` 的 `USER CODE` 区域；
- **便于联调**：预留测试点宏，可结合示波器或逻辑分析仪观察关键窗口。

---

## 硬件需求

- **开发板**：YTM32B1LE15-EVB-Q48
- **调试器**：J-LINK v9.2 或更高版本
- **外部设备**：支持 LIN Header 发送的主机节点、USB-LIN 适配器，或另一块运行 LIN Master Demo 的开发板

---

## 硬件连接

本示例默认使用开发板板载 LIN PHY，通过 UART0 与 LIN 收发器相连。测试时请将开发板接入外部 LIN 总线，并保证板载 LIN PHY 正常供电。

### 1. MCU 到板载 LIN PHY 的资源映射


| MCU 引脚 | 板级信号         | 功能说明                              |
| ------ | ------------ | --------------------------------- |
| PTA3   | LIN_UART0_TX | UART0 TX，作为 LIN 发送通道              |
| PTA2   | LIN_UART0_RX | UART0 RX，同时也是自适应阶段的 GPIO/DMA 采样输入 |
| PTD2   | LIN_SLEEP_EN | LIN PHY 使能/睡眠控制，默认输出高电平           |


### 2. 外部测试连接建议

- 将开发板 LIN 接口连接至外部 **LIN 主机节点**
- 外部主机与开发板之间需 **共地**
- 为板载 LIN PHY 的 **VBAT 提供 12V 电源**
- 主机应能够发送包含 **Break + Sync + PID** 的标准 LIN Header

### 3. 推荐联调方式

- **方式 A**：当前 Demo 作为从机，另一块 EVB 运行 `Lin_Master_Demo` 作为主机
- **方式 B**：使用 USB-LIN/CANoe/总线分析仪发送不同波特率的 Header，观察从机是否正确完成自适应同步

---

## 软件需求

- **SDK**：YTM32B1LE1_1_4_0 或更高版本
- **GCC**：GNU GCC v10.3 或更高版本
- **Keil/MDK**：ARM Keil/MDK v5.36 或更高版本
- **IAR**：IAR v8.40 或更高版本
- **VS Code**：Microsoft Visual Studio Code IDE v1.76 或更高版本（需 GNU GCC 工具链、CMake v3.25、ninja、Cortex-Debug 扩展）
- **J-LINK**：SEGGER J-LINK v6.96 或更高版本，需安装 YTM32B1LE1 支持包
- **Ozone**：SEGGER Ozone v3.28 或更高版本

---

## LIN Auto Baud Demo 实现原理

### 1. 总体流程

```text
+--------------------------+      +--------------------------+      +--------------------------+
| 1. LIN 从机按标称波特    | ---> | 2. LIN Driver 检测       | ---> | 3. RX 切到 GPIO 并开启   |
|    率等待 Header         |      |    到 Break              |      |    falling-edge DMA      |
+--------------------------+      +--------------------------+      +------------+-------------+
                                                                                 |
                                                                                 v
+--------------------------+      +--------------------------+      +------------+-------------+
| 6. DMA 回调校验 4 个     | <--- | 5. DMA 采满 5 个         | <--- | 4. pTMR 时间戳被 DMA     |
|    two-bit 间隔并预配    |      |    Sync falling 时间戳   |      |    自动搬运到内存        |
|    UART 波特率           |      |                          |      |                          |
+------------+-------------+      +--------------------------+      +--------------------------+
             |
             v
+------------+-------------+      +--------------------------+      +--------------------------+
| 7. GPIO 切到等待单次     | ---> | 8. Sync stop rising      | ---> | 9. RX 切回 UART，继续    |
|    rising-edge 中断      |      |    到来                  |      |    接收 PID / Response   |
+--------------------------+      +--------------------------+      +--------------------------+
```

流程说明如下：

1. 从机上电后先按标称波特率进入 LIN 接收状态，用于等待主机 Header 并完成 Break 识别。
2. 一旦确认进入自适应流程，软件立即接管 RX 引脚，把后续同步测量从 UART 采样切换为 GPIO falling-edge DMA 采样。
3. `pTMR` 负责提供高分辨率时间戳，DMA 每收到一次 falling-edge 请求，就把当前 `TCV` 搬运到 `s_dmaTimerValue[]`。
4. 共采集 `5` 个 falling edge 时间戳，对应 `Sync start / bit1 / bit3 / bit5 / bit7`。
5. DMA 完成后，在回调中将 GPIO 改 rising-edge，并对 `4` 个 two-bit 间隔求和平均，并估算当前总线波特率。
6. UART 波特率寄存器只在 DMA 回调里完成预配置，此时 **不会立即切回 RX PIN MUX**。
7. GPIO 改为仅等待下一次 rising-edge，该边沿必须是 `Sync stop rising`。
8. 只有在这个 rising-edge ISR 中，软件才恢复 UART RX 复用、发布 `LIN_SYNC_OK` 并继续 PID 接收。

### 2. 为什么 DMA 版比中断采样版更稳

中断采样版是在每次 GPIO ISR 进入后读取当前 `pTMR` 计数，因此单个样本会受 GPIO ISR 延迟抖动影响。DMA 版则不同：

- GPIO falling-edge 到来后，由硬件 DMA 请求直接把 `pTMR->TCV` 搬运到 RAM；
- 不再需要对每一次 falling edge 都进入 ISR 并软件读取计数器；
- 因此 falling-edge 时间戳路径对“每边沿 ISR 入口抖动”的敏感性更低。

这并不意味着 DMA 版没有实时性要求。DMA 版仍然有两个关键窗口：

1. **DMA 完成回调窗口**
  - 从第 `5` 次 falling edge 到 `Sync stop rising` 之间只有约 `1 bit` 时间；
  - 必须在这个窗口内完成 GPIO 改 rising-edge; 样本处理、目标波特率计算、`OSR/SBR` 搜索可以延迟到 PID 起始位采样前。
2. **最终 rising-edge ISR 窗口**
  - 必须在 PID 起始位采样前恢复 UART 接收路径；
  - 如果 rising-edge ISR 被阻塞过久，会导致 PID 接收不稳定。

因此客户系统仍应避免：

- 长时间全局关中断
- 长临界区
- 长时间占用 CPU 的高优先级 ISR
- 影响 DMA IRQ 和 GPIO IRQ 及时响应的系统负载

### 3. 时间测量与时钟同源要求

本 Demo 使用 `pTMR` 测量 Sync 边沿间隔，再使用 `UART` 依据该测量结果重配波特率。因此：

- **pTMR 功能时钟与 UART 功能时钟建议同源**
- 更准确地说，两者至少应来自 **同一主时钟源**，或来自同一主时钟的 **固定分频链路**
- 若两者时钟源不同，或者一个来自高精度时钟、另一个来自漂移较大的独立时钟，则会引入系统性测量误差

错误场景示意：

- `pTMR` 按时钟源 A 测得目标 bit 时间；
- `UART` 却按时钟源 B 去计算 `OSR/SBR`；
- 当 A、B 之间存在频偏时，UART 实际输出或采样波特率将偏离测量目标。

### 4. Break 检测后必须在 Sync start falling 之前进入 DMA 采样阶段

本 Demo 不再要求“第一个边沿必须是 Break 上升沿”，但仍要求：

- 当 LIN Driver 已识别到 Break 条件后（默认 `11 bit`）；
- 软件必须在 **Sync start falling 到来之前**；
- 完成 RX 引脚从 UART 到 GPIO 的切换，并开启 GPIO falling-edge DMA 请求。

原因是：

- 第一个 DMA 样本必须是 **Sync start falling**；
- 只有这样，后续 `5` 个 falling edge 的计数和 `4` 个 two-bit 间隔才与算法假设一致；
- 如果切换过晚，第一个记录到的 falling 可能已经是 `bit1 / bit3 / bit5 / bit7` 的内部边沿，导致样本错位，波特率计算失败。

时序示意如下：

```text
LIN 总线:   |_____________________|‾|_|‾|_|‾|_|‾|_|‾|_|‾|....
                Break    ^      ^   ^<--- Sync = 0x55 --->
                         |      |   |
阶段                      |      |   Sync start falling
                         |      GPIO 已切到 falling-edge DMA
                         Break 检测成功
要求: 第一个 DMA 有效 falling edge 必须是 Sync start falling
```

### 5. Sync falling-edge 采样与波特率估算

LIN Sync 字段固定为 `0x55`，其码型具有规则翻转边沿，适合通过 falling-edge 序列估算 bit 宽度。

本 Demo 中：

- 共关注 `5` 个 falling edge；
- 第 `1` 个 falling edge 对应 `Sync start falling`，仅用于建立参考时间戳；
- 第 `2~5` 个 falling edge 分别形成 `4` 个 two-bit 间隔样本；
- 先对 `4` 个 two-bit 间隔求平均，再除以 `2` 得到 `s_averageBitTimeLength`；
- 根据下式估算当前总线波特率：

```text
BaudRate = pTMR_Clock / AverageBitTime
```

边沿对应关系如下：


| Falling 次数 | 对应位置                 | 用途                                      |
| ---------- | -------------------- | --------------------------------------- |
| 第 1 次      | `Sync start falling` | 建立参考时间戳                                 |
| 第 2 次      | `bit1 falling`       | 记录第 1 个 two-bit 间隔                      |
| 第 3 次      | `bit3 falling`       | 记录第 2 个 two-bit 间隔                      |
| 第 4 次      | `bit5 falling`       | 记录第 3 个 two-bit 间隔                      |
| 第 5 次      | `bit7 falling`       | 记录第 4 个 two-bit 间隔，并立即完成波特率计算与 UART 预配置 |
| 下一次 rising | `Sync stop rising`   | 切回 UART，进入 PID 接收                       |


### 6. 波特率接受策略

DMA 版发布口径与 interrupt 版保持一致，按标称波特率窗口接受：

- `LIN_SYNC_NOMINAL_BAUD = 19200`
- `LIN_SYNC_BAUD_TOLERANCE_PERMILLE = 105`

即默认接受范围为：

```text
LIN_SYNC_NOMINAL_BAUD ± 10.5%
```

含义如下：

- 先根据 `4` 个 two-bit 间隔计算当前测得波特率；
- 再判断测得值是否落入相对标称波特率的 `±10.5%` 窗口；
- 超出该窗口则判定当前帧自适应失败，放弃当前 Header，重新等待下一帧。

### 7. UART 波特率重配策略与 0.5% 说明

计算出目标波特率后，Demo 不线性扫描全部 OSR，而是优先尝试采样质量更高的候选值：

```c
{16, 8, 32, 12, 24, 20, 4}
```

策略特点如下：

- 优先尝试更常用、采样质量更好的 OSR；
- 每次根据 `UART source clock / (OSR * Baud)` 反算 `SBR`；
- 比较反算波特率与目标值之间的偏差；
- 若误差已经小于 `0.5%`，则提前退出搜索；
- 仅在真正写 UART 寄存器时短暂关闭全局中断，缩短临界区。

这里的 `0.5%` 含义需要特别说明：

- `±10.5%` 是目标自适应范围；
- `0.5%` 是波特率重配后的搜索精度目标；
- 也就是说，软件希望在主机实际波特率落入 `±10.5%` 范围内时，尽量为 UART 找到一个误差不超过 `0.5%` 的重配结果，从而提高稳定接收概率。

当 `OSR < 8` 时，代码会自动打开 UART Both Edge Sampling，以增强低 OSR 下的采样稳定性。

### 8. stop handoff 行为

本 Demo 与 interrupt 版保持一致，最终的 `Sync stop rising` handoff 只负责完成最小必要动作：

- 关闭 GPIO 边沿捕获；
- 将 RX 引脚的 PIN MUX 切回 UART；
- 更新状态为 `LIN_SYNC_OK`；
- 推进 LIN 节点进入 `RECV_PID`；
- 继续接收随后的 PID 字段。

这里需要特别强调：

- DMA 回调只完成 **波特率计算和 UART 预配置**；
- **不会立即切回 RX PIN MUX**；
- stop rising ISR 只做 **最终路径交接**；
- 发布口径不把额外串口清理动作作为 stop handoff 的对外行为定义。

### 9. 锁定时机

当 `LIN_SYNC_AUTOBAUD_MODE` 配置为 `LIN_SYNC_MODE_STARTUP_RETRY_UNTIL_SUCCESS` 时，锁定时机与 interrupt 版保持一致：

- 不是在 `SYNC stop` 成功后立即锁定；
- 而是在 **完整帧成功结束**后锁定；
- 具体来说，应在 `LIN_RX_COMPLETED` 或 `LIN_TX_COMPLETED` 后认为首次成功同步完成。

这样做的目的，是保证“首次成功后锁定”的含义对应的是完整可用的一帧，而不是只完成了 Header 同步。

### 10. 超时与异常恢复机制

Demo 使用 `lpTMR0` 为 LIN 协议栈提供统一时间基准，用于 Header 和 Response 两阶段超时管理。

以下异常场景会触发重新挂起到下一帧 Header：

- Sync 错误
- PID 错误
- Frame 错误
- Readback 错误
- Checksum 错误
- RX Overrun
- Header 或 Response 超时

恢复动作统一由 `LinSync_RearmForNextHeader()` 完成，包括：

- 清理本地自适应状态变量；
- 关闭 GPIO 边沿捕获；
- 必要时将 LIN 节点重新切回 Idle 状态；
- 为下一帧重新准备 DMA 采样上下文。

---

## Demo 使用说明

### 1. 默认通信行为

Demo 作为 LIN 从机运行，接收到不同 PID 后执行如下动作：


| PID    | 行为   | 说明                                                           |
| ------ | ---- | ------------------------------------------------------------ |
| `0x3C` | 接收数据 | 从机调用 `LIN_DRV_ReceiveFrameData()` 接收 8 字节数据到 `s_linRxBuff[]` |
| `0x3D` | 发送数据 | 从机调用 `LIN_DRV_SendFrameData()` 发送固定 8 字节数据                   |


默认发送数据为：

```text
55 AA 69 96 96 69 AA 55
```

### 2. 关键配置项

以下内容按“客户系统影响优先”的分组方式整理。客户移植时优先关注第一组，第二组通常保持默认即可。

#### 客户必须关注的配置项


| 配置项                                                                                    | 默认值                                | 说明                                                                                                |
| -------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------- |
| `LIN_SYNC_UART_INSTANCE` / `LIN_SYNC_UART_BASE`                                        | `0 / UART0`                        | 绑定的 LIN/UART 实例，必须与实际硬件连接一致                                                                       |
| `LIN_SYNC_UART_CLOCK_NAME`                                                             | `UART0_CLK`                        | UART 功能时钟名，决定重配波特率的计算基准                                                                           |
| `LIN_SYNC_RX_GPIO` / `LIN_SYNC_RX_PIN`                                                 | `GPIOA / 2`                        | 自适应阶段的 RX 采样端口与引脚                                                                                 |
| `LIN_SYNC_RX_MUX`                                                                      | `PCTRL_MUX_ALT6`                   | RX 从 GPIO 切回 UART 时使用的复用功能                                                                        |
| `LIN_SYNC_NOMINAL_BAUD`                                                                | `19200`                            | 标称波特率，是自适应范围和超时设计的基准                                                                              |
| `LIN_SYNC_AUTOBAUD_MODE`                                                               | `LIN_SYNC_MODE_EVERY_HEADER_RECAL` | `LIN_SYNC_MODE_EVERY_HEADER_RECAL` 为每帧自适应，`LIN_SYNC_MODE_STARTUP_RETRY_UNTIL_SUCCESS` 为首次完整帧成功后锁定 |
| `LIN_SYNC_LPTMR_INSTANCE` / `LIN_SYNC_LPTMR_PERIOD_US` / `LIN_SYNC_LPTMR_TICKS_PER_US` | `0 / 520 / 48`                     | 超时服务基准，通常跟随板级时钟配置统一调整                                                                             |
| `LIN_SYNC_TIMEOUT_HEADER_TICKS` / `LIN_SYNC_TIMEOUT_RESPONSE_TICKS`                    | `5 / 15`                           | LIN 超时门限，除非协议时序整体变化，否则保持默认                                                                        |


#### 一般不建议客户修改的实现参数


| 配置项                                                   | 默认值             | 说明                                    |
| ----------------------------------------------------- | --------------- | ------------------------------------- |
| `LIN_SYNC_BAUD_TOLERANCE_PERMILLE`                    | `105`           | 对客户系统建议按相对标称波特率 `±10.5%` 理解           |
| `LIN_SYNC_PTMR_INSTANCE` / `LIN_SYNC_PTMR_CLOCK_NAME` | `0 / pTMR0_CLK` | Sync 时间戳采样资源与时钟，建议与 UART 时钟同源或同固定分频链路 |
| `LIN_SYNC_FALLING_EDGE_COUNT`                         | `5`             | Sync falling edge 总计数，和当前采样算法强绑定      |
| `LIN_SYNC_TWOBIT_SAMPLE_COUNT`                        | `4`             | 有效 two-bit 间隔样本数，和当前平均算法强绑定           |


### 3. 运行步骤

1. 使用 YCT 打开工程，确认 `UART0`、`GPIOA/PTA2`、`DMA`、`pTMR0`、`lpTMR0` 的资源配置与当前硬件一致；
2. 核对 `pTMR` 与 `UART` 功能时钟是否同源或同一固定分频链路；
3. 下载程序到 `YTM32B1LE15-EVB-Q48`；
4. 连接外部 LIN 主机，并为板载 LIN PHY 提供 `12V VBAT`；
5. 让主机发送不同波特率的 LIN Header，建议覆盖标称波特率附近以及 `±10.5%` 范围边界；
6. 主机发送 `PID=0x3C` 时，向从机下发 8 字节数据；
7. 主机发送 `PID=0x3D` 时，读取从机返回的固定 8 字节响应。

### 4. 预期结果

- 从机应能够在 Break 后进入 GPIO falling-edge DMA 采样阶段，并捕获到以 `Sync start falling` 为起点的 `5` 个 falling edge 序列；
- 第 `5` 次 falling 后，应能在 `Sync stop rising` 到来前完成 UART 波特率预配置，并在 stop rising 时切回 UART；
- 当主机发送 `PID=0x3C` 时，`s_linRxBuff[]` 中可观察到接收数据；
- 当主机发送 `PID=0x3D` 时，主机可接收到固定响应数据；
- 在 `LIN_SYNC_MODE_STARTUP_RETRY_UNTIL_SUCCESS` 模式下，应在 `LIN_RX_COMPLETED` 或 `LIN_TX_COMPLETED` 之后才锁定；
- 若主机波特率超出范围、Header 不完整，或关键窗口被抢占导致超时，Demo 应放弃当前帧并自动等待下一帧。

当前示例未内置串口打印逻辑，建议通过以下方式验证：

- 在调试器中观察 `s_currentBaudRate`、`s_averageBitTimeLength`、`s_linRxBuff[]`；
- 使用逻辑分析仪或 LIN 分析仪观察 Break、Sync、PID 以及切换窗口；
- 结合主机侧日志确认收发结果。

---

## 中断优先级与实时性约束

### 1. 默认中断优先级建议

本 Demo 的自适应流程对中断响应时间敏感，推荐配置为：


| 中断            | 推荐优先级 | 说明                                      |
| ------------- | ----- | --------------------------------------- |
| `DMA0_IRQn`   | `0`   | Sync falling 时间戳采样完成后的 DMA 回调，关键窗口最高优先级 |
| `GPIOA_IRQn`  | `0`   | `Sync stop rising` 最终切回 UART，关键窗口最高优先级  |
| `UART0_IRQn`  | `1`   | LIN 事件处理                                |
| `lpTMR0_IRQn` | `1`   | LIN 超时服务                                |


设计意图如下：

- DMA 回调与 stop rising ISR 不能被低优先级任务拖延；
- UART 预配置必须在 stop rising 到来前完成；
- stop rising ISR 必须在 PID 起始位到来前完成 UART 路径恢复；
- LPTMR 用于超时服务，但不应抢占关键采样窗口。

### 2. 三个核心实时性约束

#### 约束 A：Break 检测后必须在 Sync start falling 之前进入 DMA 采样阶段

```text
T_break_detect_to_gpio_dma_enable < T_break_ok_to_sync_start_falling
```

含义：

- 从 Break 检测成立，到 GPIO falling-edge DMA 请求真正开启之间的时间；
- 必须小于从当前时刻到 `Sync start falling` 到来的剩余时间；
- 这样第一个 DMA 有效 falling edge 才能是 `Sync start falling`。

#### 约束 B：第 5 次 falling 到 Sync stop rising 的 1 bit 窗口内必须完成 GPIO中断模式的切换

```text
T_gpio_switch_to_rising < T_bit_time
```

含义：

- 从第 `5` 次 falling edge 采样完成开始；
- 到 `Sync stop rising` 到来之前；
- 软件必须完成GPIO edge 模式切换。

#### 约束 C：Sync stop rising 到 PID 到来之间必须完成 UART 路径恢复

```text
T_stop_rising_isr + T_mux_switch_back < T_stop_to_pid
```

含义：

- 在 `Sync stop rising` 这个单次 GPIO ISR 内；
- 软件必须完成关闭 GPIO 捕获、恢复 UART RX 复用、发布 `LIN_SYNC_OK` 并推进到 `RECV_PID`；
- 以确保 UART 不会错过 PID 起始位。

### 3. 实时性窗口示意图

```text
+----------------------+     +----------------------+     +----------------------+     +----------------------+
| 1. Break 检测成立     | --> | 2. GPIO falling DMA  | --> | 3. Sync start        | --> | 4. 第 5 次 falling    |
|                      |     |    已开启            |     |    falling 到来      |     |    完成采样          |
+----------------------+     +----------------------+     +----------------------+     +----------+-----------+
                                                                                                  |
                                                                                                  v
                             +----------------------+     +----------------------+     +----------------------+
                             | 7. Sync stop rising  | <-- | 6. 计算 + 搜索       | <-- | 5. 切到 rising-edge  |
                             |    到来              |     |    + UART 预配置     |     |                      |
                             +----------+-----------+     +----------------------+     +----------------------+
                                        |
                                        v
                             +----------------------+     +----------------------+
                             | 8. MUX 切回 UART     | --> | 9. PID 起始位到来    |
                             |    + 发布 SYNC_OK    |     |                      |
                             +----------------------+     +----------------------+
```

关键窗口：

- `① -> ②`：必须在 `Sync start falling` 到来前完成；
- `④ -> ⑤`：必须落在 `1 bit` 预配置窗口内；
- `⑦ -> ⑧`：必须落在 `Sync stop rising` 到 PID 到来之间。

如果这些窗口失效，客户系统上的直接表现通常是：

- 约束 A 失败：当前 Header 无法正确进入同步，表现为偶发不同步或整帧丢失；
- 约束 B 失败：虽然已采到 falling edge，但 stop rising 前 UART 尚未预配置完成，表现为 PID 丢失或 Header 解析失败；
- 约束 C 失败：UART 切回过晚，表现为 PID 首位丢失、后续帧错误或偶发超时。

---

## 移植与调试建议

### 1. 优先确认资源映射

请首先确认以下配置与 YCT 生成结果一致：

- UART0 RX/TX 引脚复用；
- RX GPIO 端口和 PIN 号；
- GPIO falling-edge DMA 请求来源；
- DMA 通道号与中断号；
- pTMR 通道号；
- LPTMR 周期配置。

### 2. 优先观察的关键点

建议用测试点或逻辑分析仪观察：

- Break 检测完成时刻；
- GPIO/DMA falling-edge 采样开始时刻；
- DMA 完成回调执行区间；
- GPIO rising-edge ISR 执行区间；
- UART RX 恢复时刻。

### 3. 常见失败原因

- Break 后切 GPIO/DMA 太晚，导致第一个样本不是 `Sync start falling`；
- DMA 请求路由不对，导致 `s_dmaTimerValue[]` 没有采满 `5` 个样本；
- `pTMR` 与 `UART` 时钟不同源，导致测量值和 UART 重配置不一致；
- DMA 回调执行太慢，来不及在 `Sync stop rising` 前完成预配置；
- 最终 rising-edge ISR 被更高优先级任务阻塞，导致 PID 接收失败；
- 主机波特率超出相对 `LIN_SYNC_NOMINAL_BAUD` 的 `±10.5%` 接受窗口。

### 4. 文件说明

- `app/main.c`
  - 包含 DMA 版 LIN 自适应波特率核心逻辑；
  - 自适应相关代码集中在 `USER CODE` 区域，便于移植。
- `Lin_AutoBaud_Dma_Demo.yct`
  - YCT 工程配置文件，包含时钟、引脚、DMA、LIN、定时器等资源配置。
- `ReadMe_zh.md`
  - 当前中文发布说明；
  - 文档以后续统一发布口径为准，不等同于当前代码快照。

### 5. 移植建议

如需将本 Demo 迁移到客户工程，建议按以下顺序进行：

1. 先移植并验证底层资源映射：UART / GPIO / DMA / pTMR / LPTMR；
2. 再验证 Break -> Sync -> PID 的基本接收流程；
3. 再验证 DMA 是否能稳定采到 `5` 个 falling-edge 时间戳；
4. 再验证波特率接受策略、UART 预配置和 stop-rising 交接是否稳定；
5. 最后再根据客户系统负载评估中断优先级、临界区长度和实时性裕量。

---

## 总结

`Lin_AutoBaud_Dma_Demo` 展示的是一种更贴近量产场景的 LIN 从机自适应波特率实现方式：

- 用 **UART** 识别 Break；
- 用 **GPIO + DMA + pTMR** 完成 Sync 时间戳采样；
- 用 **DMA 回调** 完成波特率估算和 UART 预配置；
- 用 **单次 rising-edge GPIO ISR** 完成最终 RX 路径交接。

相较于纯 GPIO 中断采样方案，本工程显著降低了 falling-edge 样本对 ISR 延迟抖动的敏感度；同时在对外发布口径上，与 interrupt demo 保持一致的波特率接受策略、OSR 搜索方式、宏命名和锁定语义，更便于客户理解、移植和比较两种实现路径。