EDMA3高级应用:Ping-Pong缓冲与传输链技术详解

EDMA3高级应用:Ping-Pong缓冲与传输链技术详解 1. 项目概述与核心价值在嵌入式系统开发尤其是涉及高速数据流处理的领域比如音频编解码、图像处理或通信协议栈CPU常常被海量的数据搬运任务所拖累。想象一下一个麦克风正在持续采集音频数据一个ADC模数转换器正在源源不断地输出采样值如果每一个字节的搬运都需要CPU亲自参与那CPU就什么也别干了光顾着“搬砖”了。这时候DMA直接内存访问控制器就像一位专业的“搬运工”它能在外设和内存之间建立一条直达通道CPU只需要告诉它“从哪里搬搬到哪里搬多少”就可以去处理更重要的计算任务了。然而传统的DMA配置比如设置一个源地址、一个目的地址和一个传输计数虽然解放了CPU却引入了一个新的问题同步。当DMA在向一个缓冲区Buffer A填充数据时CPU无法安全地读取这个缓冲区因为数据可能正在被写入导致读到“半成品”。反之当CPU在处理另一个缓冲区Buffer B的数据时DMA也不能向它写入新数据。这就迫使CPU必须像踩着钢丝一样精确地在DMA完成传输的瞬间介入进行数据交换这在复杂的多级缓存架构和实时性要求高的场景下几乎是不可能完成的任务极易导致数据丢失或CPU等待严重制约系统性能。德州仪器TI的增强型直接内存访问控制器EDMA3为解决这一核心矛盾提供了两把“瑞士军刀”Ping-Pong缓冲和传输链。Ping-Pong缓冲通过硬件层面的双缓冲机制优雅地解耦了DMA传输与CPU处理的时间线让两者可以并行不悖。而传输链技术则像一套精密的“多米诺骨牌”或“流水线”允许单个事件触发一系列复杂的、关联的传输动作或者将一次庞大的数据搬运分解成多个小批次避免长时间独占总线资源。理解并掌握这两项技术是从“会使用DMA”到“能驾驭DMA进行高效系统设计”的关键跨越。无论你是正在调试音频接口的嵌入式软件工程师还是设计视频处理流水线的系统架构师这篇文章将带你深入EDMA3的寄存器配置细节手把手拆解这两个高级功能的实现原理与实战配置让你能真正在项目中用活它们释放硬件潜力。2. Ping-Pong缓冲原理、配置与实战精解2.1 核心思想从“接力赛”到“双车道”要理解Ping-Pong我们先摒弃“一个缓冲区”的思维定式。它的核心思想非常简单准备两套缓冲区。我们称之为Ping缓冲区和Pong缓冲区。EDMA3控制器和CPU在这两套缓冲区上玩一场“你方唱罢我登场”的游戏。工作流程如下初始状态EDMA3被配置为向Ping缓冲区写入数据或从中读取数据。第一阶段EDMA3开始工作向Ping缓冲区填充数据。与此同时CPU可以安全地处理上一轮已经填满的Pong缓冲区中的数据假设系统已初始化并开始了第一轮循环。切换信号当EDMA3完成对Ping缓冲区的操作例如填满了一个数据块它会通过中断或标志位通知CPU“Ping区好了Pong区我也用完了咱们交换吧”角色互换CPU收到信号后开始处理新鲜的Ping缓冲区数据。EDMA3则自动通过链接机制将其操作切换到Pong缓冲区覆盖掉CPU已经处理完的旧数据或者从中读取CPU准备好的新数据。循环往复上述过程持续进行形成稳定的流水线。这样做的好处是革命性的CPU和EDMA3实现了时间上的解耦。CPU不再需要“掐着表”等待DMA完成它只要确保在自己处理一个缓冲区的周期内EDMA3能完成对另一个缓冲区的操作即可。这极大地降低了软件设计的复杂性并显著提升了系统的整体吞吐量和实时响应能力。2.2 基于PaRAM链接的硬件实现机制EDMA3实现Ping-Pong的魔法藏在它的参数RAMPaRAM和“链接”Linking功能里。每个DMA通道都有一套PaRAM参数集定义了单次传输的所有属性源/目的地址、传输计数、索引等。链接功能允许一个通道在完成当前传输后自动从PaRAM的另一个指定位置加载下一套参数从而实现传输配置的自动切换。在Ping-Pong模式下我们为同一个DMA通道准备两套PaRAM集一套对应Ping缓冲区一套对应Pong缓冲区。关键在于这两套参数集的LINK字段Ping参数集的LINK字段指向Pong参数集在PaRAM中的地址偏移量。Pong参数集的LINK字段指向Ping参数集在PaRAM中的地址偏移量。这样当通道使用Ping参数集完成传输后硬件会自动加载Pong参数集下一次传输就会使用Pong缓冲区的地址。再下一次又链接回Ping参数集如此循环形成一个闭环。通道选项OPT、计数ACNT/BCNT和索引SRCBIDX/DSTBIDX等参数在Ping和Pong集中通常是相同的唯一的区别就是源地址SRC或目的地址DST它们分别指向Ping和Pong缓冲区的实际内存地址。让我们结合输入材料中的McBSP示例来具体化。假设我们通过McBSP多通道缓冲串行端口接收音频数据Ping缓冲区地址0x1180_0000Pong缓冲区地址0x1180_0800假设每个缓冲区大小为2KB即0x800字节偏移McBSP数据接收寄存器DRR地址0x01D0_0000使用DMA通道3来将数据从DRR搬移到内存。我们需要配置两个PaRAM集比如Set 3Ping和 Set 64Pong。Set 3 (Ping) 关键参数DST:0x1180_0000(Ping缓冲区地址)LINK:0x4820(这是Set 64的地址偏移量计算方式后文详述)Set 64 (Pong) 关键参数DST:0x1180_0800(Pong缓冲区地址)LINK:0x4800(这是Set 3的地址偏移量)初始化时我们将通道3的PaRAM指针指向Set 3。当第一次传输到Ping缓冲区完成EDMA3自动加载Set 64的参数下一次传输目标就变成了Pong缓冲区。当第二次传输完成又通过Set 64的LINK字段跳回Set 3完美实现乒乓切换。注意LINK字段是字节偏移地址且必须32字节对齐低5位为0。PaRAM中每个参数集固定为8个32位字32字节。因此Set N的起始地址偏移量是N * 32或N 5。例如Set 3的偏移是3 * 32 96 0x60但文档中示例的LINK值0x4800和0x4820是特定于其PaRAM基地址的绝对地址或经过换算的值。在实际编程中我们通常使用类似EDMA3_PARAM_SET_X的宏或基地址偏移来计算。关键是要理解“Ping链向PongPong链向Ping”这个闭环逻辑。2.3 CPU与EDMA3的同步策略硬件自动切换缓冲区了CPU怎么知道该处理哪一块呢这就需要同步机制。EDMA3提供了传输完成中断TCINT功能。我们可以在通道的OPT参数中启用TCINTEN位并设置TCC传输完成码为一个特定值比如3对应通道号。当一次传输无论是到Ping还是Pong完成时EDMA3控制器会在中断挂起寄存器IPR中设置对应的位例如IPR[3] 1。CPU可以通过两种方式获知中断模式使能相应中断让CPU进入中断服务程序ISR进行处理。这是最高效、最实时的方式。轮询模式CPU定期检查IPR寄存器的相应位。这种方式软件开销大实时性差仅在简单或低负载系统中使用。在中断服务程序或轮询处理函数中CPU需要判断当前EDMA3正在使用哪个缓冲区这通常通过一个软件标志位来跟踪例如currentBuffer PING。处理非当前的缓冲区即EDMA3刚刚填满的那个。因为EDMA3在触发中断时已经切换到另一个缓冲区开始工作了。清除IPR中的中断挂起位。更新软件标志位。// 伪代码示例 volatile enum {BUFFER_PING, BUFFER_PONG} activeDmaBuffer BUFFER_PING; volatile uint32_t *pingBuffer (uint32_t*)0x11800000; volatile uint32_t *pongBuffer (uint32_t*)0x11800800; void EDMA3_Channel3_ISR(void) { // 1. 判断哪个缓冲区已就绪与activeDmaBuffer相反 volatile uint32_t *dataToProcess; if (activeDmaBuffer BUFFER_PING) { dataToProcess pongBuffer; // DMA刚写完Pong正在写Ping } else { dataToProcess pingBuffer; // DMA刚写完Ping正在写Pong } // 2. 处理数据 (例如进行音频滤波、编码等) processAudioData(dataToProcess, BUFFER_SIZE); // 3. 清除中断标志位 (具体寄存器操作依赖驱动库) EDMA3ClrIntr(3); // 例如清除IPR[3] // 4. 可选更新软件状态但这不是必须的因为硬件链接已决定下一块缓冲区 // activeDmaBuffer (activeDmaBuffer BUFFER_PING) ? BUFFER_PONG : BUFFER_PING; // 注意不要在此处修改DMA的DST地址硬件链接已自动处理。 }2.4 实战配置步骤与避坑指南假设我们使用TI的C6000系列DSP和其驱动程序库如TI的SYS/BIOS或裸机寄存器操作配置一个McBSP接收的Ping-Pong DMA流程如下步骤一内存分配与对齐确保Ping和Pong缓冲区在内存中是连续且对齐的。根据数据大小和缓存行大小Cache Line Size通常是32或64字节进行对齐可以避免缓存一致性问题提升性能。#define BUFFER_SIZE_IN_BYTES (2048) // 2KB #define CACHE_LINE_SIZE (64) #pragma DATA_ALIGN(pingBuffer, CACHE_LINE_SIZE) uint8_t pingBuffer[BUFFER_SIZE_IN_BYTES]; #pragma DATA_ALIGN(pongBuffer, CACHE_LINE_SIZE) uint8_t pongBuffer[BUFFER_SIZE_IN_BYTES];步骤二初始化EDMA3控制器启用EDMA3模块时钟进行必要的全局初始化通常由启动代码或驱动完成。步骤三配置PaRAM集这是核心步骤。我们需要填充两个PaRAM集。以下以寄存器级思维描述实际使用库函数会更简洁。计算地址获取pingBuffer和pongBuffer的物理地址注意在启用MMU或缓存时可能需要转换为物理地址或使用缓存一致性操作。配置Ping参数集例如Set 3OPT: 使能传输完成中断(TCINTEN1)设置TCC3。根据同步类型A-sync或AB-sync设置SYNCDIM。SAM/DAM设置为递增模式。SRC: McBSP DRR地址 (0x01D0_0000)。DST:pingBuffer的物理地址。ACNT: 每次传输的元素大小例如McBSP接收一个字为4字节则ACNT4。BCNT: 每个缓冲区包含多少这样的元素例如BUFFER_SIZE_IN_BYTES / 4。LINK:指向Pong参数集Set 64的地址偏移。BCNTRLD: 通常等于BCNT用于A同步传输后重载。配置Pong参数集例如Set 64除DST改为pongBuffer物理地址LINK改回指向Set 3的偏移外其他参数与Ping集完全相同。步骤四配置DMA通道并启动将通道3的PaRAM入口指向Set 3Ping集。在事件使能寄存器EER中使能通道3的事件例如对应McBSP接收事件。在中断使能寄存器IER中使能TCC3对应的中断。配置McBSP使其在接收到数据时触发EDMA3事件如REVT。步骤五编写中断服务程序如上文伪代码所示在ISR中处理数据并清除中断标志。避坑指南与实操心得缓存一致性Cache Coherency这是最大的坑如果CPU和DMA共享的缓冲区位于可缓存Cacheable内存区域你必须手动维护缓存一致性。在DMA写入后、CPU读取前需要无效化InvalidateCPU缓存中对应缓冲区的行以确保CPU读到的是内存中最新的数据由DMA写入。在CPU写入后、DMA读取前需要写回Writeback或清空Flush缓存行以确保DMA看到的是CPU写入的最新数据。许多现代处理器如ARM Cortex-A/R和DSP如C66x提供了硬件加速器如Cache Coherent Interconnect或专用的内存区域Non-cacheable或Write-Back Write-Allocate with coherence来简化此问题但理解原理至关重要。缓冲区大小与传输计数匹配确保ACNT * BCNT等于你分配的缓冲区大小。一个常见的错误是ACNT设置错误如地址递增单位是字节但数据宽度是字导致数据错位或缓冲区溢出。链接地址计算务必确保LINK地址是32字节对齐的并且指向一个有效的、已初始化的PaRAM集。错误的链接地址会导致DMA加载到随机参数系统行为不可预测甚至崩溃。首次启动系统上电后Ping和Pong缓冲区可能都是空的。你需要一种机制来启动这个“乒乓”循环。通常的做法是手动触发一次DMA传输例如通过写ESR寄存器或者让外设产生第一个事件。同时软件需要初始化activeDmaBuffer状态以知道第一个就绪的缓冲区是哪个。中断风暴如果传输非常频繁中断开销可能变得显著。确保你的ISR尽可能高效。在极端高性能场景可以考虑使用轮询结合低功耗模式或者使用EDMA3的传输完成链Transfer Complete Chaining将中断合并下文会讲到。3. 传输链技术原理、场景与高级应用3.1 传输链的本质事件驱动的自动化流水线如果说Ping-Pong缓冲解决了“生产者-消费者”同步问题那么传输链Transfer Chaining技术则解决了“复杂任务编排”和“资源公平性”问题。它的核心思想是利用一次传输的完成事件自动触发另一次传输。这就像设置了一套自动化流水线或多米诺骨牌。EDMA3实现了两种链传输完成链TCCHEN在一次传输的整个PaRAM集完全耗尽即所有维度的传输都完成时触发。中间传输完成链ITCCHEN在一次传输的每个中间数组Array完成时触发对于A同步传输每个事件触发一个数组对于AB同步传输每完成一个B维度的数组触发一次。链的“触发”表现为在链事件寄存器CER中设置一个位这个位的位置由PaRAM中OPT参数的TCC字段指定。当CER中的某个位被置起它就像一个软件手动写入事件置位寄存器ESR一样可以触发另一个DMA通道开始传输只要那个通道被使能且映射到对应的事件。3.2 应用场景一单事件服务多外设FIFO对输入材料中的第一个例子非常经典用单个外部事件如一个GPIO中断同时服务一对输入/输出FIFO。场景描述系统有两个外部FIFO一个用于输入数据一个用于输出数据。它们需要以相同的速率被服务。理想情况下一个“数据就绪”信号例如来自输入FIFO的非空标志应该能同时触发对输入FIFO的读取DMA输到内存和对输出FIFO的写入DMA从内存传输出去。传统难题这需要两个DMA事件也就可能需要两个外部中断引脚。传输链解决方案将GPIO事件例如GPINT0映射为DMA事件16配置为触发主通道例如通道16的传输。该通道负责从输入FIFO读取数据。在通道16的PaRAM设置中启用中间传输完成链ITCCHEN1并设置TCC31假设我们想链式触发事件31。配置另一个DMA通道例如通道31负责向输出FIFO写入数据并将其事件使能映射到链事件31即CER[31]。当GPIO事件到来触发通道16开始传输一个数据块数组。在该数组传输完成的瞬间中间传输完成EDMA3硬件会设置CER[31]1这相当于自动产生了一个对通道31的触发事件。通道31被触发执行向输出FIFO的写入传输。由于是AB同步传输或连续事件这个过程会为每个数据块重复从而实现用一个外部事件同步了两个DMA通道。配置要点通道16主通道的OPTITCCHEN1,TCC31(目标链事件)TCCHEN可能也需要设置用于最终完成中断。通道31从通道的OPTTCINTEN根据需要设置其触发源是链事件31因此其对应的EER中事件31的使能位需打开。两个通道的SYNCDIM需要仔细设计以确保读写节奏匹配。通常都配置为A同步这样每个GPIO脉冲触发一对读写操作。3.3 应用场景二大块传输分解与时间片化这是传输链另一个极其重要的应用将一次大的数据传输任务分解成多个小的数据包传输。问题背景一个高优先级的、巨大的DMA传输例如从内部RAM搬运16MB数据到外部SDRAM会长时间占用EDMA3的传输队列和内存总线。这会“饿死”starve同队列中其他低优先级的DMA请求甚至影响CPU和其他主设备对内存的访问严重损害系统实时性和响应能力。解决方案利用中间传输完成链ITCCHEN让这个大任务“自己链自己”实现自动分片。配置方法设定一个合理的“数据包”大小例如1KB这个大小要保证单次传输耗时不会过长能允许其他任务插入。配置DMA通道例如通道25进行一个A同步传输。ACNT 数据包大小例如1024字节。BCNT 总数据量 / 数据包大小例如 16384 / 1024 16。CCNT 1。SYNCDIM A同步。在该通道的OPT参数中启用中间传输完成链ITCCHEN1并将TCC设置为自身的通道号25。同时启用传输完成中断TCINTEN1用于在所有分片传输完成后通知CPU。通过写事件置位寄存器ESR[25]1手动启动第一次传输。工作流程CPU写ESR[25]触发通道25传输第一个1KB数据包数组0。第一个数据包传输完成中间传输完成。由于ITCCHEN1且TCC25硬件自动设置CER[25]1。CER[25]1作为一个链事件再次触发通道25因为它映射到了事件25开始传输第二个1KB数据包数组1。此过程自动重复直到BCNT递减到0表示所有16个数据包传输完毕。最终传输完成时由于TCINTEN1产生一个中断通知CPU任务完成。核心优势时间片化在每个1KB数据包传输的间隙EDMA3控制器有机会处理同一队列中其他等待的传输请求。这相当于为这个大任务引入了“休息点”提高了系统的公平性和响应性。简化软件CPU只需要发起一次传输所有分片和连续传输都由硬件自动完成软件无需用循环来多次触发DMA。保持原子性从逻辑上看这仍然是一个完整的16KB传输但物理上被分割执行兼顾了效率和公平。3.4 传输链的寄存器级深度解析要精准配置传输链必须理解几个关键寄存器通道选项参数OPTITCCHEN中间传输完成链使能。置1后每次中间传输完成非最后一次都会触发链。TCCHEN传输完成链使能。置1后整个传输最后一次完成时触发链。TCC(6位)传输完成码。指定链或中断发生时在CER或IPR中设置哪一位0-63。这是链接的“目标地址”。ITCINTEN/TCINTEN控制是否在中间/最终完成时产生中断。链事件寄存器CER这是一个只写寄存器对CPU而言。当ITCCHEN或TCCHEN条件满足时硬件会根据TCC值自动设置CER的对应位。该位被置起后其效果等同于向事件置位寄存器ESR的对应位写1会触发映射到该事件号的DMA通道。CER中的位在触发相应通道后不会自动清除但通常我们不需要手动清除它因为硬件在触发事件后其作用已完成。如果需要可以通过写链事件清除寄存器CECR来清除。事件使能寄存器EER与映射一个链事件如CER[31]要能触发一个DMA通道如通道2必须满足① 该通道的事件被使能EER[31]1② 该通道的PaRAM集已正确配置。通常DMA通道号与事件号有默认映射关系但也可能通过DMAQNUMx等寄存器重映射需要查阅具体芯片手册。配置流程总结确定逻辑明确是“一触多发”场景一还是“自触自分”场景二。规划事件号为主通道和从通道分配TCC值事件号。确保它们不冲突且在设备支持范围内。配置从通道配置好执行实际传输的从通道PaRAM并确保其对应的事件在EER中被使能。配置主通道链在主通道PaRAM的OPT中设置ITCCHEN/TCCHEN和TCC指向从通道的事件号或自身事件号用于分片。启动触发主通道的事件外部事件或软件写ESR。4. 高级技巧、性能优化与调试实战4.1 Ping-Pong与传输链的联合使用在实际的高性能系统中Ping-Pong和传输链常常结合使用构建出复杂而高效的数据流。例如在一个音频处理流水线中Ping-Pong输入McBSP通过DMA通道3Ping-Pong模式将采集的音频数据存入内存缓冲区A和B。链式触发处理当通道3输入DMA完成一个缓冲区的填充并触发中断时在中断服务程序中我们不直接处理数据而是启动一个传输链。处理流水线这个传输链可以包含多个步骤链第一步触发一个DMA通道如通道4将刚填满的音频缓冲区数据搬运到DSP的L2 SRAM速度更快进行处理。链第二步通过中间链或完成链触发另一个DMA通道如通道5将处理后的结果从L2 SRAM搬移到输出缓冲区另一个Ping-Pong对。链第三步最终触发输出外设如McBSP发送端或DAC的DMA发送通道。输出Ping-Pong输出端同样配置为Ping-Pong模式确保数据输出的连续性。这样从数据采集、搬运、处理到输出形成了一条由DMA硬件高度自动化管理的流水线CPU仅在关键节点如算法处理介入极大提升了系统效率。4.2 性能优化考量缓冲区大小与延迟权衡Ping-Pong缓冲区越大CPU处理的时间窗口越宽松但数据处理的端到端延迟也越大。需要根据实时性要求如音频的buffer周期选择合适的大小。通常缓冲区大小是单次DMA传输计数ACNT*BCNT的整数倍。内存布局与缓存将Ping-Pong缓冲区放在高速低延迟的内存中如芯片内SRAM。如果必须放在外部DDR务必注意缓存一致性操作带来的开销有时直接使用非缓存Non-cacheable区域可能更简单高效。队列优先级EDMA3通常有多个传输队列Queue。将高实时性、小数据量的传输如音频采样放在高优先级队列将大数据量、低实时性的传输如背景数据搬运放在低优先级队列。利用传输链的分片功能可以防止低优先级大任务阻塞高优先级队列。参数集PaRAM规划芯片的PaRAM空间有限。合理规划PaRAM集的分配避免冲突。Ping-Pong需要两个集复杂传输链可能需要更多。可以将不常用的配置动态加载到PaRAM中。4.3 调试技巧与常见问题排查调试EDMA3问题尤其是涉及Ping-Pong和链式传输时逻辑比较复杂。以下是一些实用的调试思路寄存器检查当DMA不工作时首先检查事件使能寄存器EER对应通道的事件是否使能中断使能寄存器IER中断是否使能如果用了中断事件寄存器ER/中断挂起寄存器IPR是否有事件发生或中断挂起可以通过软件写ESR来手动触发事件进行测试。PaRAM内容使用调试器直接查看PaRAM区域的内存确认你写入的参数地址、计数、链接是否正确。链接地址错误是最常见的问题之一。使用调试器观察在数据传输的源和目的地址设置内存访问断点或观察点。当数据被写入时触发断点可以确认DMA是否在正确工作。观察缓冲区内容看数据是否按预期填充。简化测试先配置最简单的单次传输确保基础功能正常。然后逐步增加复杂度先实现Ping-Pong再添加传输链。常见问题速查表现象可能原因排查步骤DMA完全不传输1. 事件未使能EER2. 外设未正确触发事件3. PaRAM地址配置错误如NULL4. 传输计数为01. 检查EER寄存器2. 检查外设配置尝试软件写ESR触发3. 用调试器查看PaRAM内容4. 检查ACNT/BCNT/CCNTPing-Pong不切换1. LINK字段配置错误未形成闭环2. 未启用链接功能OPT中相关位3. 缓冲区地址未正确更新到PaRAM1. 仔细计算并核对Ping和Pong集的LINK值2. 链接是自动的无需特别使能但需确认PaRAM已写入3. 确认写入的DST地址是物理地址且正确传输链不触发1. ITCCHEN/TCCHEN未使能2. TCC值设置错误与目标通道事件不匹配3. 目标通道的事件未使能EER4. 链事件被屏蔽或清除1. 检查主通道OPT2. 确认TCC值检查目标通道的事件映射3. 检查目标通道的EER4. 检查是否有其他逻辑错误清除了CER数据错位或覆盖1. SRCBIDX/DSTBIDX计算错误2. 缓冲区大小与传输计数不匹配3. Ping和Pong缓冲区地址重叠或计算错误1. 重新计算地址索引2. 确认ACNT*BCNT*CCNT 缓冲区大小3. 打印或检查缓冲区地址系统卡死或异常1. 缓存一致性问题最常见2. 访问了非法内存地址3. 中断嵌套或处理时间过长1. 在DMA操作前后加入缓存维护操作Clean/Invalidate2. 检查所有内存地址的有效性3. 优化ISR或考虑使用轮询利用EDMA3的错误寄存器EDMA3控制器有错误寄存器如CCERR可以指示地址对齐错误、配置错误等。在初始化后和出错时检查这些寄存器能快速定位硬件层面的配置问题。掌握EDMA3的Ping-Pong和传输链本质上是在学习如何让硬件更智能地管理数据流将CPU从繁琐的搬运工作中彻底解放出来。这需要你对系统内存布局、外设特性、中断机制都有清晰的认识。开始时可能会觉得寄存器配置繁琐但一旦打通其带来的性能提升和系统设计的简洁性是巨大的。建议从芯片厂商提供的驱动库或示例代码入手先让一个简单的例子跑起来再逐步修改参数观察现象最终达到完全掌控的目的。