1. 高速接口数据流管理的核心挑战
在嵌入式图像处理、汽车摄像头或者工业视觉系统的开发中,我们经常需要处理来自图像传感器(Image Sensor)的海量像素数据。这些数据通过LVDS或MIPI CSI-2这类高速串行接口,以每秒数百兆甚至上千兆比特的速率涌入处理器。这就像一条汹涌澎湃的数据大河,而我们的处理系统(如DSP或SoC)则是下游的蓄水池和处理工厂。如果河水来得太猛太快,蓄水池(硬件缓冲区)来不及处理就会溢出,导致数据丢失,画面出现花屏或撕裂;如果河水断流,下游工厂就会“饿死”,处理流程中断。因此,如何精准地控制这条数据河的流量,确保其平稳、持续地流入处理单元,就成了嵌入式底层驱动开发中最核心也最棘手的问题之一。
德州仪器(TI)在其许多带有高速接口(HSI)模块的处理器中,提供了一个名为CBUFF(Circular Buffer)的硬件缓冲区,并配套了一套精密的寄存器配置机制,专门用来解决这个“控流”难题。这套机制的核心,就是一系列以CFG_DATA_LLx(Link List,链表)和CFG_DATA_LLx_THRESHOLD命名的寄存器。很多工程师在初次接触这些寄存器时,往往只关注数据格式、包长等“显性”参数,而对FIFO阈值这类“隐性”配置一知半解,结果就是系统在压力测试下频频出现偶发性丢帧或卡顿,排查起来犹如大海捞针。今天,我就结合自己踩过的坑,把这套数据流控制的“阀门”原理和配置实战讲透,让你在设计和调试LVDS/CSI-2数据通路时,心里更有底。
2. CBUFF FIFO:数据流中的关键“蓄水池”
要理解阈值配置,首先得搞清楚CBUFF在整个数据通路中的角色。你可以把它想象成连接数据源(如ADC Buffer或DMA)和数据消费者(LVDS/CSI-2协议引擎)之间的一个“蓄水池”或“中转仓库”。
数据写入侧(上游):通常是DMA控制器,它从内存或前级模块(如ADC)疯狂地搬运数据,并试图写入CBUFF。DMA的写入速度受总线带宽、仲裁等因素影响,可能是不稳定或突发的。
数据读出侧(下游):是LVDS或CSI-2的协议引擎(Protocol Engine),它按照固定的像素时钟频率,从CBUFF中读取数据,并串行化发送出去。这个读出速率相对稳定,由视频时序(如分辨率、帧率)决定。
CBUFF本身是一个先入先出(FIFO)的硬件队列。它的核心矛盾在于:写入速度和读出速度的动态匹配。理想情况下,写入均值等于读出均值,FIFO深度维持在一个半满的稳定状态。但现实是,DMA传输可能有延迟,或者协议引擎可能因行/帧消隐期而暂停读取,导致速度瞬时失配。
如果FIFO被写满(上溢),新来的数据无处可放,就会丢失。如果FIFO被读空(下溢),协议引擎无数据可发,输出就会产生错误(如CSI-2的ECC错误或LVDS的同步丢失)。CFG_DATA_LLx_THRESHOLD寄存器里的WR_THRESHOLD(写阈值)和RD_THRESHOLD(读阈值),就是用来主动管理这两种风险的关键“水位线”传感器和控制开关。
注意:这里的“LLx”(如LL17, LL18)指的是不同的数据链路(Link List)条目。在TI HSI的架构中,一个复杂的数据流(如一帧图像中的不同区域或不同虚拟通道的数据)可以被分解成多个链表条目依次描述。每个条目都有自己独立的配置寄存器组,包括数据属性(
CFG_DATA_LLx)和流控阈值(CFG_DATA_LLx_THRESHOLD)。这意味着你可以为数据流的不同阶段设置不同的流控策略,非常灵活。
3. 核心寄存器详解:从数据描述到流控阈值
输入材料中给出了从LL17到LL23的多组寄存器,它们的结构高度相似。我们以CFG_DATA_LL18和CFG_DATA_LL18_THRESHOLD这一组为例,进行深度拆解。理解了这一组,其他组触类旁通。
3.1 数据属性配置寄存器:CFG_DATA_LL18
这个寄存器(偏移地址0x108)定义了通过这条链表传输的数据包的所有基本属性。它就像一份“发货清单”,告诉硬件:要发什么货、怎么包装、发到哪里。
关键字段解析:
LL18_SIZE (Bits 22-9):
- 作用:配置本次传输的数据大小。这是最需要仔细计算的字段之一。
- 单位:样本数(Samples),而不是字节数。手册明确说明,一个Sample对应一个16位的CBUFF单元。这是很多人的第一个坑。如果你的数据是YUV422格式(每个像素16位),那么一个Sample就是一个像素。如果你的数据是RAW10(每个像素10位,但打包成16位存储),也需要按16位单元来计算。
- 配置示例:假设你要传输一行1280像素的RGB565图像(每个像素16位)。那么
LL18_SIZE就应该配置为1280。如果数据是32位对齐的(例如ARGB8888),但CBUFF单元是16位,那么你需要将32位数据视为2个Samples,LL18_SIZE应为像素数 * 2。
LL18_FMT (Bits 6-5)与LL18_FMT_IN (Bit 8):
LL18_FMT:指定输出到LVDS/CSI-2线缆上的数据格式。00代表16-bit,01代表14-bit,10代表12-bit。这决定了协议引擎如何将CBUFF中的16位单元映射到串行位宽上。例如,选择12-bit时,每个16位Sample的高12位会被发送,低4位被忽略。LL18_FMT_IN:指定输入到CBUFF的数据对齐方式。0表示128位对齐,1表示96位对齐。这告诉DMA或前级模块,数据在内存或总线上的组织方式。必须与数据源的实际对齐方式匹配,否则会导致数据错位。- 关联与陷阱:
FMT_IN和FMT不一定相同!FMT_IN关乎数据如何“存入”仓库(CBUFF),FMT关乎数据如何“取出”并发送。例如,数据源以128位块(8个16位Sample)提供RAW12数据,FMT_IN设为0。但输出时你想每Sample只发送12位以节省带宽,FMT就可设为10。硬件会自动处理位宽的转换和打包。
LL18_LPHDR_EN (Bit 27)与LL18_LPHDR_VAL (独立寄存器):
- CSI-2模式:
LPHDR_EN置1,表示这个链表条目是一个新长数据包的开始。协议引擎在发送实际数据前,会先发送一个长包包头(Long Packet Header)。包头内容由LL18_LPHDR_VAL寄存器指定,通常包含数据标识(Data ID)、包长度(WC)等信息。这是构建符合MIPI CSI-2协议的数据流所必需的。 - LVDS模式:
LPHDR_EN置1,表示这是一个新LVDS帧的开始。此时LL18_LPHDR_VAL通常被固定配置为0xBBBBBBBB,作为一个帧起始的同步标记或保留字段。 - 实操心得:在连续传输一帧图像时,通常只在第一个链表条目(描述帧起始)设置
LPHDR_EN=1,后续的条目(描述同一帧内的连续数据)设为0,以避免产生多余的包头,影响数据连续性。
- CSI-2模式:
LL18_HS (Bit 2)与LL18_HE (Bit 1):
- CSI-2模式:分别控制是否在数据前后发送行同步(HSYNC)短包。用于标记图像的行开始和行结束。
- LVDS模式:
HS标记该条目数据是LVDS帧内的第一个数据;HE标记是最后一个数据。用于帧同步。 - 配置逻辑:对于一行图像数据,通常设置
HS=1, HE=1。对于一帧内连续的多行数据块,可能第一行HS=1,中间行HS=0, HE=0,最后一行HE=1。这需要根据具体的传感器输出时序来设计。
LL18_VALID (Bit 0):
- 这是条目的“总开关”。只有设为
1,该链表条目才会被硬件执行。在动态更新链表(如Ping-Pong Buffer)时,通过清零此位可以��全地禁用某个条目。
- 这是条目的“总开关”。只有设为
3.2 流控阈值配置寄存器:CFG_DATA_LL18_THRESHOLD
这个寄存器(偏移地址0x110)是数据流稳定的“定海神针”。它不关心数据内容,只关心CBUFF FIFO的“水位”。
核心字段深度剖析:
LL18_WR_THRESHOLD (Bits 14-8):
- 功能:配置CBUFF FIFO的写阈值。当FIFO中未被读取的数据量(即存量)达到或超过这个阈值时,CBUFF会向DMA发出“停止写入”的信号(通常是通过反压,如拉高
DMA_READY信号或产生一个中断),从而暂停(Stall)DMA的写入操作。 - 目的:防止FIFO上溢(Overflow)。这是保护机制,确保下游消费速度跟不上时,上游不会继续灌水导致数据丢失。
- 值域与计算:该字段占7位,理论值范围0-127(
0x7F)。复位默认值是0x3F(十进制63)。这个阈值代表的是FIFO中以16位Sample为单位的数量。 - 如何设置:
- 保守策略:设置一个较高的值(如100)。这给了FIFO较大的缓冲空间,能容忍DMA的突发写入,但风险是一旦FIFO接近满,DMA被暂停后,需要较长时间才能将水位降到阈值以下恢复写入,可能影响平均吞吐率。
- 激进策略:设置一个较低的值(如32)。DMA会较早被暂停,使得FIFO水位维持在较低水平,响应更灵敏。但缓冲能力弱,对下游读取速度的瞬时波动更敏感。
- 经验值:一个常见的起点是设置为FIFO总深度的一半到三分之二。假设CBUFF FIFO总深度为128个Sample,可以设置
WR_THRESHOLD = 80(约62.5%深度)。这既提供了足够的缓冲,又留出了安全余量。必须结合你的DMA突发长度和协议引擎的“饥饿”容忍度来权衡。
- 功能:配置CBUFF FIFO的写阈值。当FIFO中未被读取的数据量(即存量)达到或超过这个阈值时,CBUFF会向DMA发出“停止写入”的信号(通常是通过反压,如拉高
LL18_RD_THRESHOLD (Bits 6-0):
- 功能:配置CBUFF FIFO的读阈值。当FIFO中累积的数据量达到或超过这个阈值时,CBUFF才允许协议引擎开始从中读取数据并发送出去。
- 目的:防止FIFO下溢(Underflow),并优化启动延迟。这是启动机制,确保协议引擎一开始发送,就有足够连续的数据,避免刚发几个Sample就断粮。
- 值域与计算:占7位,范围0-127。复位默认值是0。
- 如何设置:
- 设为0:意味着FIFO中一有数据(哪怕只有1个Sample),协议引擎就开始发送。这延迟最低,但极容易因DMA写入的微小延迟而导致下溢,产生发送错误。除非你的DMA写入速度绝对稳定且远超读取速度,否则不建议设为0。
- 合理设置:通常设置为一个足以覆盖DMA最大延迟的数值。例如,如果DMA响应一次请求的最大延迟是传输20个Sample的时间,那么
RD_THRESHOLD至少应设为20。对于视频流,考虑到行消隐期后DMA重新启动的延迟,可以设置为一行数据量的1/4或1/8。例如,一行1280像素,可以设置RD_THRESHOLD = 160(1280/8)。
- 与WR_THRESHOLD的联动:
RD_THRESHOLD<WR_THRESHOLD是基本前提。它们之间形成了一个“缓冲区工作窗口”。当数据量低于RD阈值,不发送;当数据量在RD和WR阈值之间,正常收发;当数据量达到WR阈值,暂停写入。这个窗口的宽度决定了系统应对速度波动的能力。
ll18dman (Bits 18-16):
- 功能:当
LPHDR_EN使能时(即一个新数据包/帧开始),CBUFF可以通过哪个硬件请求线(DMA HW Req line)向DMA控制器发起传输请求。 - 作用:实现基于数据包的DMA触发。这对于动态调度不同数据源非常有用。例如,你可以将虚拟通道0的数据映射到DMA通道0(dman=0),虚拟通道1的数据映射到DMA通道1(dman=1),实现硬件级的流控和多路复用。
- 配置:值0-6对应不同的硬件请求线,值7表示不触发DMA。需要与SOC的DMA控制器配置相匹配。
- 功能:当
4. 实战配置流程与参数计算示例
假设我们要为一个130万像素(1280x1024)的CMOS传感器配置CSI-2输出,帧率30fps,像素格式为RAW10(10位数据打包在16位中)。我们将使用一个链表条目(LL18)来描述一整行数据的传输。
4.1 第一步:确定基本参数与数据量
- 分辨率:1280 x 1024
- 像素位深:10-bit (RAW10),但存储和传输以16位单元进行。
- 帧率:30 fps
- 接口:MIPI CSI-2,1个数据通道(1 Lane)。
- 计算一行数据的Sample数:
- 每像素对应1个16位Sample(尽管只用了10位)。
- 一行数据量(Sample数) = 水平像素数 = 1280。
- 因此,
LL18_SIZE = 1280(十进制) =0x500(十六进制)。注意,该字段是14位(Bits 22-9),最大可表示16383,足够。
4.2 第二步:配置CFG_DATA_LL18寄存器
我们需要将计算出的值和模式选择填入寄存器。假设使用虚拟通道0,需要发送HSYNC包。
// 假设寄存器基地址为 HSI_BASE volatile uint32_t *reg_ll18 = (uint32_t*)(HSI_BASE + 0x108); uint32_t ll18_value = 0; // 1. 设置数据大小:1280个Samples (0x500) // Bits[22:9] = 0x500, 需要左移9位 ll18_value |= (0x500 << 9); // 2. 设置输入格式:假设数据源是128位对齐的(常见于DMA从内存搬运) // Bit[8] = 0 (128-bit aligned) // ll18_value |= (0 << 8); // 默认为0,可不设置 // 3. 设置输出格式:RAW10对应12-bit输出?这里需要澄清。 // RAW10在CSI-2中通常以10-bit格式传输,但CBUFF的FMT字段是12/14/16。 // 实际上,对于10-bit数据,通常仍选择16-bit输出格式,由协议引擎处理打包。 // 或者,有些实现中,FMT选择12-bit,高10位为有效数据。 // 这里假设我们选择16-bit输出,FMT=00。 // Bits[6:5] = 0b00 // ll18_value |= (0 << 5); // 默认为0,可不设置 // 4. 设置虚拟通道号:VC=0 // Bits[4:3] = 0b00 // ll18_value |= (0 << 3); // 默认为0,可不设置 // 5. 使能HSYNC和HEnd包:这是一行数据的开始和结束 // Bit[2] HS = 1 (发送HSYNC Start) // Bit[1] HE = 1 (发送HSYNC End) ll18_value |= (1 << 2) | (1 << 1); // 6. 使能长包包头(因为是CSI-2数据包) // Bit[27] LPHDR_EN = 1 ll18_value |= (1 << 27); // 7. 使能CRC校验(如果数据来自ADC Buffer,根据需求开启。此处假设不需要) // Bit[28] CRC_EN = 0 (默认) // 8. 最后,必须使能该链表条目 // Bit[0] VALID = 1 ll18_value |= 0x1; // 写入寄存器 *reg_ll18 = ll18_value;4.3 第三步:配置长包包头值 (CFG_DATA_LL18_LPHDR_VAL)
对于CSI-2,长包包头(32位)包含:8位数据标识(Data ID),16位包长度(WC),8位ECC。
- Data ID:包含虚拟通道号(VC)和数据类型(DT)。假设VC=0,DT for RAW10 = 0x2B。
- 数据标识 = (VC << 6) | DT = (0 << 6) | 0x2B = 0x2B。
- WC (Word Count):包数据长度,以字节为单位。注意,这里和
LL18_SIZE单位不同!- 一行数据字节数 = Sample数 * 2字节/Sample = 1280 * 2 = 2560 字节。
- WC = 2560。
- ECC:包头错误校验码,由前面的24位(Data ID + WC)计算得出(通常硬件自动计算或可配置)。 假设我们手动配置一个包头,其中ECC先设为0(实际中可能由硬件填充或需计算)。
volatile uint32_t *reg_lphdr = (uint32_t*)(HSI_BASE + 0x10C); uint32_t lphdr_value = 0; // 组装长包包头: [ECC(8) | WC(16) | Data ID(8)] // 假设 Data ID = 0x2B, WC = 2560 (0xA00) lphdr_value = (0x00 << 24) | // ECC 暂为0 (0x0A00 << 8) | // WC = 2560 (0x2B); // Data ID *reg_lphdr = lphdr_value;4.4 第四步:���键!配置流控阈值 (CFG_DATA_LL18_THRESHOLD)
这是性能调优的核心。我们需要估算合理的读写阈值。
已知条件:
- FIFO总深度(假设):128 Samples(根据常见设计)。
- 一行数据量:1280 Samples。
- DMA突发传输长度(假设):64 Samples(128字节,一个常见的Cache行对齐长度)。
- 协议引擎读取速度:稳定,一行数据在行有效期内均匀读完。
计算与策略:
写阈值(WR_THRESHOLD):
- 目标:防止上溢,同时尽量减少DMA暂停次数。
- 考虑:DMA一次突发写入64 Samples。我们希望在一次突发写入后,FIFO水位不要超过安全线。同时,要留出空间应对DMA可能因总线竞争产生的延迟。
- 设置:
WR_THRESHOLD = FIFO深度 - DMA突发长度 - 安全余量 = 128 - 64 - 16 = 48。 - 解释:当FIFO中数据达到48个Sample时,就暂停DMA。这样即使一个64 Sample的突发立刻到来,FIFO水位最高会到48+64=112,仍小于总深度128,有16个Sample的安全余量。我们将
48写入Bits 14-8。
读阈值(RD_THRESHOLD):
- 目标:防止下溢,确保协议引擎启动时有足够数据。
- 考虑:协议引擎开始读取后,DMA需要时间响应并填充数据。这个延迟包括DMA启动延迟和首次传输延迟。
- 设置:
RD_THRESHOLD = 估计的DMA响应延迟内消耗的Sample数 + 启动缓冲。 - 估算:假设DMA响应延迟最坏情况是消耗掉32个Sample的时间。为了更稳健,我们再加一些缓冲。
- 设置:
RD_THRESHOLD = 32 + 16 = 48。但注意,RD_THRESHOLD必须小于WR_THRESHOLD。我们上面设置了WR=48,因此RD必须小于48。调整一下,设RD_THRESHOLD = 32。 - 解释:当FIFO中累积了32个Sample后,协议引擎才开始发送。这给了DMA一个“提前量”去准备数据。
DMA请求线(ll18dman):假设使用DMA通道0,则设置为0。
volatile uint32_t *reg_threshold = (uint32_t*)(HSI_BASE + 0x110); uint32_t threshold_value = 0; // 1. 设置写阈值 WR_THRESHOLD = 48 (0x30) threshold_value |= (0x30 << 8); // Bits[14:8] // 2. 设置读阈值 RD_THRESHOLD = 32 (0x20) threshold_value |= (0x20 << 0); // Bits[6:0] // 3. 设置DMA请求线为0 // Bits[18:16] = 0 // threshold_value |= (0 << 16); // 默认为0,可不设置 // 写入寄存器 *reg_threshold = threshold_value;4.5 第五步:启动与监控
配置完所有链表条目(本例只有一个LL18,实际一帧可能需要多个条目循环)后,使能HSI模块的DMA和协议引擎。然后,通过监控CBUFF的状态寄存器(如果有)或使用调试工具(如逻辑分析仪抓取DMA请求/应答信号、FIFO水位信号)来观察实际运行情况。
关键监控点:
- FIFO水位是否大部分时间在RD和WR阈值之间波动?
- DMA是否频繁被暂停(Stall)?如果是,可能需要增大WR_THRESHOLD或优化DMA优先级。
- 协议引擎是否曾因FIFO为空而停顿(下溢)?如果是,可能需要增大RD_THRESHOLD或检查DMA性能。
5. 常见问题排查与调试技巧
在实际项目中,配置不当会导致各种诡异问题。下面是一个典型的问题排查清单。
| 现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 图像随机出现单行/多行花屏或数据错位 | 1.FIFO上溢:WR_THRESHOLD设置过高,或DMA突发过快,导致数据被覆盖。 2.链表SIZE计算错误:单位弄错(字节 vs Sample),或数值溢出。 3.数据对齐(FMT_IN)错误:源数据对齐方式与配置不符。 | 1.检查上溢:尝试显著降低WR_THRESHOLD(如设为20)。如果问题消失或变化,说明是流控问题。需重新评估DMA性能和FIFO深度,适当降低WR阈值或优化DMA传输模式(如减小突发长度)。2.核对SIZE:确认 LLx_SIZE是以16位Sample为单位。对于RAW10/12等格式,确认计算无误。用简单图案(如彩条)测试,核对接收端数据量。3.验证对齐:确保 FMT_IN与数据源(如内存中的图像缓冲区)的对齐方式一致。128位对齐是常见选择。 |
| 图像开始部分正常,后续出现断流、黑屏或绿色画面 | 1.FIFO下溢:RD_THRESHOLD设置过低,或DMA延迟过大,导致协议引擎“饿死”。 2.DMA未正确触发: llxdman配置错误,或DMA通道未正确初始化。3.链表条目未循环或VALID位被错误清除。 | 1.检查下溢:增大RD_THRESHOLD(如从0改为32)。如果图像能持续更久,则证实是下溢。需要分析DMA延迟原因(总线负载、仲裁优先级)。2.检查DMA触发:使用示波器或芯片的GPIO toggle功能,监测DMA硬件请求线是否有信号。确认 LPHDR_EN和llxdman配置匹配。3.检查链表状态机:如果是多条目循环,确认最后一个条目的 NEXT_PTR指向第一个条目,且所有条目VALID=1。监控链表指针寄存器,看是否在循环。 |
| CSI-2数据包解析错误(如ECC错误、同步丢失) | 1.长包包头(LPHDR)配置错误:WC或Data ID不正确。 2.HS/HE控制位错误:导致行同步包时序混乱。 3.FIFO下溢导致包不完整。 | 1.解码包头:用MIPI协议分析仪抓取CSI-2数据,检查长包包头的WC和Data ID是否与配置一致。特别注意WC的单位是字节。 2.检查同步包:确认HS/HE只在需要时置位。对于连续的多行传输,中间行的HS/HE应为0。 3.结合下溢排查。 |
| LVDS输出无信号或信号不稳定 | 1.LVDS帧首尾标识错误:HS/HE在LVDS模式下配置错误,未正确标记帧开始和结束。2. LPHDR_VAL静态值未配置:LVDS模式下,LPHDR_EN置1时,LPHDR_VAL需配置为0xBBBBBBBB。3.时钟或电气问题:非寄存器配置问题,需检查时钟源、串行器配置、差分线阻抗。 | 1.核对帧结构:确认用于帧开始和结束的链表条目正确设置了HS=1和HE=1。2.检查静态头:确认 CFG_DATA_LLx_LPHDR_VAL寄存器已写入0xBBBBBBBB。3.基础检查:测量LVDS时钟和数据线是否有差分信号输出。确认LVDS串行器的参考时钟和电源正常。 |
| 性能不达标,达不到理论带宽 | 1.DMA频繁被Stall:WR_THRESHOLD设置过小,DMA有效工作时间被压缩。 2.FIFO深度成为瓶颈:对于高带宽数据,FIFO深度不足,即使优化阈值也无济于事。 3.总线带宽瓶颈:DMA读取内存的带宽不足。 | 1.优化阈值:在保证不上溢的前提下,尝试提高WR_THRESHOLD,给DMA更长的连续工作时间。2.评估FIFO深度:这是硬件限制。如果计算出的理想工作窗口(WR-RD)大于FIFO深度,则需考虑降低分辨率、帧率或使用更深的FIFO型号。 3.系统级优化:确保图像缓冲区位于高速内存(如DDR),并配置DMA使用高效的总线主端口和突发传输。 |
调试心得:
- 从简到繁:初始调试时,先用一个最简单的、固定的图案(如全红、棋盘格)进行测试。这能排除图像内容复杂度和传感器端的变量。
- 善用静态配置:在动态链表(Linked List)模式工作不稳定时,可以尝试先配置成静态模式(如果硬件支持),即只用一个链表条目循环发送固定数据。这能验证最基本的CBUFF到协议引擎的通路是否正常。
- 水位线可视化:如果芯片提供CBUFF FIFO的水位状态寄存器,一定要在调试代码中定期读取并打印或绘图。观察水位线在RD和WR阈值之间的波动情况,是调整阈值最直接的依据。
- 阈值设置不是一劳永逸的:���同的分辨率、帧率、DMA负载场景下,最优的阈值可能不同。在产品压力测试(高低温、复杂场景)时,需要重新审视和微调这些参数。
6. 高级应用:多虚拟通道与动态链表管理
在更复杂的应用中,例如多路摄像头数据复用(通过CSI-2的虚拟通道),或者发送一帧中包含多种数据类型(如图像数据+嵌入式数据),就需要用到多个链表条目(LL17-LL23)以及动态管理。
多虚拟通道示例: 假设要通过CSI-2交替发送来自两个摄像头的数据(VC0和VC1)。
- 配置LL18:描述VC0的一行数据。设置
VCNUM=0,LPHDR_EN=1(每帧开始),配置好对应的阈值。 - 配置LL19:描述VC1的一行数据。设置
VCNUM=1,LPHDR_EN=1。 - 设置链表指针:将LL18的
NEXT_PTR(通常在一个独立的链表控制寄存器中)指向LL19的地址,将LL19的NEXT_PTR指回LL18,形成一个环。 - 流控隔离:LL18和LL19有各自独立的
THRESHOLD寄存器。这意味着你可以为两个数据流设置不同的流控策略。例如,如果VC0的数据优先级更高,可以给LL18设置更宽松的WR阈值(更大),给LL19设置更严格的WR阈值(更小),确保VC0的数据流更不易被阻塞。
动态链表管理: 在“乒乓缓冲”(Ping-Pong Buffer)场景中,CPU或另一个协处理器需要动态更新下一个要发送的数据块地址。
- 准备两套链表条目(例如LL18和LL19),分别指向Buffer A和Buffer B。
- 初始时,使能LL18(
VALID=1),禁用LL19(VALID=0),链表指针环为 LL18 -> LL18。 - 当LL18描述的数据正在发送时,CPU可以安全地更新LL19中的
SIZE、DMA地址等参数,指向新的数据(Buffer B)。 - 在LL18的数据发送完成、下一次循环开始前,CPU将LL19的
VALID置1,并将LL18的NEXT_PTR修改为指向LL19。这样,下一次传输就会自动跳转到新的数据块。 - 关键点在于时机,必须在硬件使用当前条目结束后、开始根据
NEXT_PTR获取下一个条目之前,完成对下一个条目的更新和链接操作。这通常需要配合中断或状态轮询。
通过对CFG_DATA_LLx和CFG_DATA_LLx_THRESHOLD这套寄存器的深入理解和精心配置,你就能真正驾驭LVDS/CSI-2高速数据流,在嵌入式视觉系统中构建出稳定、高效的数据传输通道。这不仅仅是照着手册填几个十六进制数,更是对系统实时性、稳定性和资源利用率的深度优化。