# Lin_AutoBaud_Interrupt_Demo

---

## 功能描述

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

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

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

需要特别说明的是，本 Demo 的 Sync 时间测量属于**软件时间戳方案**，不是硬件输入捕获锁存方案：

- GPIO 检测到边沿后，软件在 **GPIO ISR 内**读取当前 `pTMR` 计数
- 单个相邻间隔来看，测得结果本质上等于“真实边沿间隔 + 相邻两次中断响应延迟之差”
- 但本 Demo 最终不是只用某一个单独间隔，而是把 `4` 个 two-bit 间隔求和后再取平均，因此**中间几次 falling 的中断延迟大多会相互抵消**
- 最终保留下来的主要误差项，来自**第 1 次 falling 参考点**与**第 5 次 falling**之间的中断响应延迟差
- 如果自适应窗口内存在 **全局关中断、长临界区、高优先级 ISR 长时间占用 CPU** 等情况，并且这类阻塞落在首末关键采样点附近，就会把这部分延迟差折算为 bit 时间测量误差
- 对客户系统而言，这不仅是“可能超时”的问题，也会直接影响波特率估算精度、PID 接收稳定性以及边界波特率兼容性

**默认配置：**

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

**功能特性：**

- **自动波特率同步**：Break 检测后进入 GPIO falling-edge 采样流程，第 `5` 次 falling 完成计算与 UART 预配置，再切到 rising-edge 等待 `Sync stop rising`；支持通过宏配置为 `每帧自适应` 或 `首次成功后锁定`
- **时间戳测量**：在 `GPIO ISR` 中读取 `pTMR0 CH0` 当前计数，记录 `5` 个 Sync falling edge 时间戳，并对 `4` 个 two-bit 间隔求平均
- **快速重配 UART**：基于 OSR 候选表 `{16, 8, 32, 12, 24, 20, 4}` 搜索最优 `OSR/SBR`
- **0.5% 搜索精度目标**：并非表示总线容差只有 `0.5%`，而是用于保证在目标 `±10%` 波特率偏差范围内仍能稳定完成重配
- **单文件移植**：自适应核心逻辑集中在 `app/main.c` 的 `USER CODE` 区域，方便客户移植
- **可调试**：预留测试点宏，可接入 GPIO 翻转，便于示波器或逻辑分析仪观测关键窗口

---

## 硬件需求

- **开发板**：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 采样输入 |
| 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 JLINK 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 中断     |
+--------------------------+      +--------------------------+      +------------+-------------+
                                                                                 |
                                                                                 v
+--------------------------+      +--------------------------+      +------------+-------------+
| 6. 计算平均 bit 宽度     | <--- | 5. GPIO 切到 rising-     | <--- | 4. pTMR 记录 5 个        |
|    搜索 OSR 并预配置     |      |    edge 等待 stop        |      |    Sync falling edge     |
+------------+-------------+      +--------------------------+      +--------------------------+
             |
             v
+------------+-------------+      +--------------------------+      +--------------------------+
| 7. Sync stop rising      | ---> | 8. 到来时 RX 切回 UART   | ---> | 9. 继续接收 PID /        |
|    到来                  |      |    并发布 SYNC_OK        |      |    Response              |
+--------------------------+      +--------------------------+      +--------------------------+
```

流程说明如下：

1. 从机上电后先按标称波特率进入 LIN 接收状态，用于等待主机 Header 并完成 Break 识别。
2. 一旦确认进入自适应流程，软件立即接管 RX 引脚，把后续同步测量从 UART 采样切换为 GPIO falling-edge 采样。
3. `pTMR` 负责给 Sync 字段提供高分辨率时间戳。第 `1` 个 falling edge 只作为参考点，后续 `4` 个 falling 间隔分别对应 `2 bit` 宽度。
4. 在第 `5` 次 falling edge ISR 内，软件首先**立即将 GPIO 中断模式切到 rising-edge**，防止后续耗时计算导致错过边沿。
5. 随后完成平均 bit 宽度换算、目标波特率计算以及 `OSR/SBR` 搜索预配置。
6. 下一次 rising edge 被视为 `Sync stop rising`，此时软件才会关闭 GPIO 捕获、恢复 UART RX 复用并继续接收 PID。
7. 当同步成功后，LIN 外设恢复正常收发路径；若同步失败或超时，则丢弃当前帧并重新等待下一帧 Header。

### 2. 时间测量、时钟同源与中断响应要求

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

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

除时钟同源外，还需要关注**中断响应一致性**。本 Demo 并不是在外设硬件里锁存边沿时间，而是在 GPIO ISR 进入后才读取 `pTMR` 当前值，因此单个区间可近似理解为：

```text
Timestamp(n) = EdgeTime(n) + IrqLatency(n)
MeasuredDelta = RealDelta + [IrqLatency(n) - IrqLatency(n-1)]
```

本 Demo 最终对 `4` 个 `two-bit` 样本求和平均，因此进一步可写成：

```text
AverageMeasuredDelta
= (Delta2 + Delta3 + Delta4 + Delta5) / 4
= AverageRealDelta + [IrqLatency(5) - IrqLatency(1)] / 4
```

这意味着：

- 如果各个采样边沿的中断响应延迟基本恒定，固定延迟大多会在相邻差分中相互抵消
- 对最终平均结果来说，中间第 `2~4` 次 falling 的中断延迟会在求和时相互抵消
- 因此最终测量误差主要取决于**第 `1` 次 falling 参考点**和**第 `5` 次 falling 完成点**的中断响应延迟是否一致
- 一旦首末两个关键采样点之一被额外拉长，后续计算得到的 `s_averageBitTimeLength` 与 `s_currentBaudRate` 就会偏离真实总线波特率
- 因此客户系统必须保证：在 **Break -> Sync -> PID** 这一小段窗口内，GPIO 采样路径具备**有界、可重复、可验证**的中断响应时间

错误场景示意：

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

另一个常见误差场景是：

- 第 `1` 个 Sync falling edge 参考点在很短延迟内进入 GPIO ISR
- 第 `5` 个 Sync falling edge 恰好遇到全局关中断或更高优先级 ISR 长时间占用
- 软件较晚才读取 `pTMR`，导致整体平均 bit 时间被额外拉长
- 最终表现为当前帧波特率估算偏低，或者虽然估算成功但 PID 接收稳定性下降

### 3. Break 检测后必须在 Sync start falling 之前进入自适应阶段

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

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

原因是：

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

时序示意如下：

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

再用窗口图表示：

```text
+----------------------+     +----------------------+     +----------------------+
| 1. 检测到 Break 条件   | --> | 2. 软件进入自适应阶段   | --> | 3. RX 切 GPIO        |
+----------------------+     +----------------------+     +----------+-----------+
                                                                     |
                                                                     v
+----------------------+     +----------------------+     +----------------------+
| 6. 开始记录第 1 个有   | <-- | 5. Sync start        | <-- | 4. 开启 falling-edge |
|    效边沿             |     |    falling 到来      |     |    中断              |
+----------------------+     +----------------------+     +----------------------+
```



### 4. 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 接收 |

### 5. 第 5 次 falling 到 stop rising 的 1 bit 窗口内必须完成 UART 预配置

这是本 Demo 最关键的**实时性约束**之一。

在第 `5` 次 falling edge 完成后（即在第 5 次 falling edge 的 ISR 内），软件需要执行：

1. **立即将 GPIO 中断模式从 falling-edge 切到 rising-edge**（防止后续耗时计算错过边沿）；
2. 对 `4` 个 two-bit 样本做平均；
3. 计算平均 bit 宽度与目标波特率；
4. 搜索 `OSR/SBR`；
5. 更新 UART `BAUD/CTRL1`（**注意：此时仅配置 UART 波特率，暂不切回 PIN MUX**）。

当紧接着的 **Sync stop rising**（上升沿）到来时，触发最后一次 GPIO 中断，软件需要执行：

1. **关闭 GPIO 边沿中断**（结束本次自适应采样）；
2. **将 RX 引脚的 PIN MUX 立即切回 UART**（恢复硬件接收路径）；
3. **更新状态为 `LIN_SYNC_OK`**，准备接收随后的 PID 字段。

第 5 次 falling 的计算与预配置动作必须全部落在 **bit7 falling 到 Sync stop rising** 的 `1 bit` 时间窗口内。只有当这 1 bit 窗口内的预配置全部完成，系统才能在 rising 中断里从容地切回 MUX，且 MUX 切换动作必须在 **PID 起始位到来前** 完成。

详细时序如下：

```text
LIN 总线:
Sync                                           PID
..‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|_________________________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|......,
                        ^                        ^                          ^
                        |                        |                          |
                        |                        Sync stop rising            sync stop end
                        第 5 次 falling（bit7 falling）

软件窗口:
                         [切 GPIO 到 rising-edge]     [切 PIN MUX 到 UART]
                        <- 必须在 1 bit 窗口内完成 -><-- 必须在 PID 开始前完成 -->
                        [计算平均 bit 宽度]
                        [搜索 OSR / SBR]
                        [重配 UART]
                       <-------------- 必须在 2 bit 窗口内完成 --------------->
```

流程图表示：

```text
+----------------------+     +----------------------+     +----------------------+     +----------------------+
| 1. 第 5 次 Sync       | --> | 2. 立即切 GPIO 到     | --> | 3. 计算平均 bit 宽度   | --> | 4. 换算目标波特率      |
|    falling 完成采样   |     |    rising-edge       |     |                      |     |                      |
+----------------------+     +----------------------+     +----------------------+     +----------+-----------+
                                                                                                  |
                                                                                                  v
                             +----------------------+     +----------------------+     +----------------------+
                             | 7. Sync stop rising  | <-- | 6. 写 UART           | <-- | 5. 搜索 OSR/SBR      |
                             |    到来前完成          |     |    BAUD/CTRL1        |     |                      |
                             +----------------------+     +----------------------+     +----------------------+
```



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

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

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

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

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

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

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

- 清理自适应状态变量
- 关闭 GPIO 边沿捕获
- 必要时将 LIN 节点重新切回 Idle 状态

---

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

### 4. 预期结果

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

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

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

---

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

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

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


| 中断            | 默认优先级 | 说明                          |
| ------------- | ----- | --------------------------- |
| `GPIOA_IRQn`  | `0`   | Sync falling 采样与 stop rising 切回 UART，优先级最高 |
| `UART0_IRQn`  | `1`   | LIN 事件处理                    |
| `lpTMR0_IRQn` | `2`   | LIN 超时服务，可低于 UART 与采样路径      |


设计意图如下：

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

这里还需要补充一个容易被忽略的点：

- GPIO 路径的优先级不仅影响“会不会错过窗口”，还直接影响“测得的 bit 时间是否准确”
- 因为本方案在 ISR 中读取 `pTMR` 当前值，所以**首末关键 falling 边沿到 ISR 的响应差**会进入最终测量误差
- 这也是为什么客户系统若引入较长的关中断时间、长耗时高优先级 ISR，可能在没有完全超时的情况下，依然出现边界波特率下的偶发失步或 PID 误码

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

#### 约束 A：Break 检测后必须在 Sync start falling 之前进入自适应阶段

```text
T_break_detect_to_gpio_enable < T_break_ok_to_sync_start_falling
```

含义：

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

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

```text
T_gpio_switch_rise_interrupt < T_bit_time
```

含义：

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

#### 约束 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      | --> | 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 到来之间

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

- 首末关键采样点的中断响应差过大：平均 bit 时间偏移，表现为估算波特率在帧间波动、边界波特率兼容性下降
- 约束 A 失败：当前 Header 无法正确进入同步，表现为偶发不同步或整帧丢失
- 约束 B 失败：虽然已采到 falling edge，但 stop rising 前 UART 尚未预配置完成，表现为 PID 丢失或 Header 解析失败
- 约束 C 失败：UART 切回过晚，表现为 PID 首位丢失、后续帧错误或偶发超时


---

## 移植与调试建议

### 1. 移植时必须核对的内容

- `UART0_RX` 的引脚复用与 GPIO 端口定义必须一致
- `pTMR` 与 `UART` 功能时钟必须同源，或来自同一固定分频链路
- `lpTMR` 配置需要与 LIN Driver 的超时服务周期匹配
- YCT 中的中断号、回调安装和引脚复用要与 `main.c` 宏定义保持一致

### 2. 使用限制与注意事项

- Demo 默认假设 **GPIO 中断捕获到的第一个有效 falling edge 是 Sync start falling**
- Demo 默认要求在 **第 5 次 falling 到 Sync stop rising 的 1 bit 窗口内完成 UART 重配置**
- Demo 默认要求在 **Sync stop rising 这个单次 GPIO ISR 内切回 UART 模式**
- Demo 默认要求在 **第 1 次与第 5 次 Sync falling 这两个关键采样点附近**不出现不可控的中断响应延迟差，尤其要避免长时间全局关中断、长临界区以及长耗时高优先级 ISR
- 若客户系统无法保证上述实时性，应优先考虑降低该窗口内的软件负载，或改用DMA搬运边沿时间的实现方案
- 文档对外说明的目标自适应范围为 **相对标称波特率 ±10%**
- `0.5%` 为 **重配搜索精度目标**，用于提高在 `±10%` 范围内稳定接收的概率
- 若更换目标板卡或外设实例，需同时修改 UART、GPIO、pTMR、lpTMR 资源映射

### 3. 调试建议

- 可在 `LIN_SYNC_TESTPOINT_ENABLE` 宏下接入 GPIO 翻转逻辑，使用示波器观测关键时间点
- 建议至少观测以下信号：LIN_RX、测试点 GPIO、UART RX 复用切换时刻
- 建议在客户系统负载最重的场景下重复观测 `Break -> Sync -> PID` 窗口，确认没有被 RTOS 临界区、高优先级周期中断或 Flash 操作拉长
- 若同步失败，优先检查主机 Header 是否规范、VBAT 是否稳定、LIN PHY 是否已使能
- 若发生误码或偶发丢帧，优先检查中断优先级、系统负载、时钟同源性及两段关键窗口是否被压缩

---
